How to test @Cacheable?

The first problem with SettingRepositoryIT is, the @Mock anotation on the field settingRepository. This is paradox for any normal-test, integration-test or any else.

You should let Spring bring in the dependencies for the class-under-test, which is SettingRepository in your case.

Please look at this example how @Autowired is used for the class-under-test, which is OrderService in this example:

@RunWith(SpringRunner.class)
// ApplicationContext will be loaded from the
// static nested Config class
@ContextConfiguration
public class OrderServiceTest {

    @Configuration
    static class Config {

        // this bean will be injected into the OrderServiceTest class
        @Bean
        public OrderService orderService() {
            OrderService orderService = new OrderServiceImpl();
            // set properties, etc.
            return orderService;
        }
    }

    @Autowired
    private OrderService orderService;

    @Test
    public void testOrderService() {
        // test the orderService
    }

}

Go for the documentation with the full example: § 15. Integration Testing

The second problem is that you do not have to test @Cachable. You should only test your implementation. Here is a very good example from Oliver Gierke on how you should test it: How to test Spring's declarative caching support on Spring Data repositories?


In my case I wanted to validate the expression in the unless expression in the @Cacheable annotation, so I think it makes perfect sense and I'm not testing Spring's code.

I managed to test it without using Spring Boot, so it is plain Spring test:

@RunWith(SpringRunner.class)
@ContextConfiguration
public class MyTest {

    private static MyCacheableInterface myCacheableInterfaceMock = mock(MyCacheableInterface.class);

    @Configuration
    @EnableCaching
    static class Config {

        @Bean
        public MyCacheableInterface myCacheableInterface() {
            return myCacheableInterfaceMock;
        }

        @Bean
        public CacheManager cacheManager() {
            return new ConcurrentMapCacheManager("myObject");
        }
    }

    @Autowired
    private MyCacheableInterface myCacheableInterface;

    @Test
    public void test() {
        when(myCacheableInterfaceMock.businessMethod(anyString())).then(i -> {
            List<MyObject> list = new ArrayList<>();
            list.add(new MyObject(new Result("Y")));
            return list;
        });
        myCacheableInterface.businessMethod("test");
        verify(myCacheableInterfaceMock).businessMethod(anyString());
        myCacheableInterface.businessMethod("test");
        verifyNoMoreInteractions(myCacheableInterfaceMock);
    }
}

In MyCacheableInterface I have the following annotation:

public interface MyCacheableInterface {
    @Cacheable(value = "myObject", unless = "#result.?[Result.getSuccess() != 'Y'].size() == #result.size()")
    List<MyObject> businessMethod(String authorization);
}