Cobertura не распознает полностью проверенный класс

В настоящее время я борюсь с тем, что Cobertura не распознает покрытие кода для данного класса при определенных обстоятельствах. Хотя класс полностью протестирован (покрытие метода 100%), Cobertura показывает покрытие 0%.

В том же пакете есть и другие классы, которые дают правильные результаты покрытия кода, поэтому неправильные шаблоны исключения в этом случае не проблема.

Тестируемый класс выглядит следующим образом:

@Service
public class CacheEnabledService {

    @Autowired
    private UserRepository userRepository;


    @Cacheable(value="users",key="#root.methodName")
    public List<User> findAllUser() {
        return userRepository.findAll();
    }
}

Сам тест:

@DirtiesContext
@ContextConfiguration(classes = {TestConfig.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class CacheEnabledServiceTest {

    @Autowired
    private CacheEnabledService cacheEnabledService;


    @Test
    public void testCachedRepoisotryFindAll(){
        UserRepository mockedRepository = Mockito.mock(UserRepository.class);
        cacheEnabledService.setUserRepository(mockedRepository);

        Mockito.when(mockedRepository.findAll()).thenReturn(Lists.<User>newArrayList(new User()));

        List<User> allExpandables1 = cacheEnabledService.findAllUser();
        List<User> allExpandables2 = cacheEnabledService.findAllUser();

        assertEquals(1, allExpandables1.size());
        assertEquals(allExpandables1.size(), allExpandables2.size());
        assertSame(allExpandables1.get(0), allExpandables2.get(0));

        Mockito.verify(mockedRepository, VerificationModeFactory.times(1)).findAll();
        Mockito.verifyNoMoreInteractions(mockedRepository);
    }
}

Мое единственное предположение до сих пор заключалось в том, что, возможно, механизмы проксирования и/или кэширования Springs мешают инструментам Coberturas.

Любые подсказки, как решить эту проблему, приветствуются. Заранее спасибо.

ОБНОВЛЕНИЕ: добавление интерфейса к классу службы устранило проблему. Отсутствующие интерфейсы корректно обрабатываются Spring, но для этого требуются некоторые манипуляции с CGLIB. В моем случае эти переназначения CGLIB переиграли Cobertura. Таким образом, всегда проверяйте, используют ли ваши службы Spring интерфейс, если у вас есть проблемы с повторным сопоставлением.


person u6f6o    schedule 06.09.2013    source источник
comment
Пахнет, как будто АОП переназначает классы. Что произойдет, если вы распечатаете cacheEnabledService.getClass().getName() или проверите, если cacheEnabledService.getClass() == CacheEnabledService.class Я подозреваю, что вы обнаружите, что они не являются одним и тем же классом... и поскольку Cobertura отслеживает классы, для которых вызываются методы, это может объяснить, почему вы видите покрытие, которое вы видите.   -  person Stephen Connolly    schedule 06.09.2013
comment
вы используете что-то вроде Maven и имеете несколько модулей, над которыми выполняются тесты?   -  person Bruce Lowe    schedule 06.09.2013
comment
@BruceLowe да, у нас есть многомодульная сборка с maven. Как вы думаете, почему это имеет значение?   -  person u6f6o    schedule 06.09.2013
comment
Что произойдет, если вы запустите тестовое покрытие только для этого класса? В проекте, над которым я работал, у меня была та же проблема, но когда я запускал ее только для этого класса, охват составлял 100%.   -  person Tom Jonckheere    schedule 07.09.2013


Ответы (1)


Просто предположил, исходя из предоставленной информации:

(1) Если вы запускаете многомодульный проект maven, вы можете обнаружить, что тест в другом модуле заполняет кеш метода @Cacheable. Cobertura работает только на уровне модуля, а не на уровне проекта. Поэтому, если тест из модуля A вызывает метод @Cacheable из модуля B, он может заполнить кеш, однако это не учитывает покрытие кода метода модуля B.

Тест, который впоследствии запускается в модуле B, получит кэшированный результат и не попадет в этот метод, поэтому cobertura может подумать, что этот метод не был охвачен.

Я вижу, вы портите контекст. Это должно очистить кеш ПОСЛЕ запуска тестов, а не до этого, так что это не гарантирует, что кеш не будет заполнен до запуска вашего теста.

ЕСЛИ это возможная причина, я бы порекомендовал вам очистить кеш вручную перед началом теста.

Для этого попробуйте внедрить диспетчер кеша с помощью @Autowired, а в разделе @Before используйте диспетчер кеша, чтобы очистить кеш этого метода.

Попробуйте и посмотрите, решена ли ваша проблема с покрытием.

(2) Если это не решит эту проблему, я бы склонялся к тому, что это одна из тех кобертур, которые плохо справляются с проблемами прокси-сервера - возможно, CacheEnabledService реализует интерфейс, и тестирование интерфейса решит это (не уверен, что это поможет, но попробовать стоит)

(Возможно, стоит также посмотреть, дает ли удаление @Cacheable охват, чтобы убедиться, что это определенно аннотация, которая является основной причиной проблемы)

person Bruce Lowe    schedule 07.09.2013
comment
Извините за мой поздний ответ и спасибо за подсказки, которые указали мне правильное направление! Пока я проверял ваши предложения, я вдруг понял, что у моего класса обслуживания нет интерфейса. Afaik, Spring использует CGLIB для обработки отсутствующих интерфейсов и применяет некоторое повторное сопоставление. После того, как я добавил интерфейс, Cobertura заработала как положено. Таким образом, добавление интерфейсов к вашим сервисам по-прежнему актуально, особенно если вы используете Cobertura. - person u6f6o; 16.09.2013
comment
Отлично, я это уже замечал. Жаль, что вам нужно ввести интерфейс для решения проблемы. Я никогда не был поклонником интерфейса для 1 реализации. - person Bruce Lowe; 16.09.2013
comment
Я полностью согласен. На мой взгляд, определение интерфейса только для одной реализации не имеет особого смысла. - person u6f6o; 16.09.2013