문제

I am currently struggling with Cobertura not recognising code coverage for a given class in certain circumstances. Although the class is fully tested (method coverage 100%), Cobertura displays a coverage of 0%.

There are other classes as well in the same package that get the right code coverage results, thus wrong exclude patterns are no issue in this case.

The class to be tested looks as follows:

@Service
public class CacheEnabledService {

    @Autowired
    private UserRepository userRepository;


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

The test itself:

@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);
    }
}

My only assumption so far was that maybe either Springs proxying and/or caching mechanisms interfere with Coberturas instrumentations.

Any hints how to solve this issue are welcome. Thanks in advance.

UPDATE: Adding an interface to the service class fixed the issue. Missing interfaces are handled correctly by Spring but some CGLIB manipulation is required to achieve this. In my case these re-mappings by CGLIB outmanoeuvred Cobertura. Thus always check if your Spring services use an interface if you have re-mapping issues.

도움이 되었습니까?

해결책

Just speculating based on the information given:

(1) If you run a multi-module maven project, you may find a test in a different module populates the @Cacheable method's cache. Cobertura only works at a module level, not project level So if a test from Module A calls a @Cacheable method from module B, it may populate the cache, however that does not count towards code coverage of module B's method.

A test that subsequently runs in module B will then get a cached result and not go into that method, hence cobertura might think that method was not covered.

I can see you are dirtying the context. This should clear the cache AFTER the tests run though, and not before - so that will not ensure the cache is not populated before your test is run.

IF this is the possible cause, I'd recommend you clear the cache manually before the test starts.

To do this try inject the cache manager with an @Autowired, and in the @Before section use the cache manager to clear the cache of that method.

Give that a try and see if your coverage problem is solved.

(2) If that doesnt solve it, I'd lean towards it being one of those cobertura not playing well with proxy issues - possibly making the CacheEnabledService implement an interface and testing against the interface will solve that (not sure if that will help, but its worth a try)

(It might be worth also seeing if removing the @Cacheable gives it coverage, to see if that is definitely the annotation which is the root cause of the issue)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top