I am using spring caching layer in my application and I have got an issue as part of writing unit tests to test spring cache layer using Mockito.
Please refer the below code for my problem:
Service layer:
public CustomerServiceImpl implements CustomerService {
@Autowired
private CacheManager cacheManager;
@Autowired
private CustomerRepository customerRepository;//Repository is simple JPA repository interface which contains findByCustomerName()
@Override
@CachePut(value = "#customer", key = "#customer.customerName")
public Customer insertOrUpdate(Customer customer) {
return customerRepository.save(customer);
}
@Cacheable(value="customersCache", key = "#customerName")
public Customer findByCustomerName(String customerName) {
Customer customer = customerRepository.findByCustomerName(customerName);
return customer;
}
}
JUnit test Code for Service layer:
@RunWith(PowerMockRunner.class)
@PrepareForTest(CustomerServiceImplTest.class)
public class CustomerServiceImplTest {
@Spy
CacheManager cacheManager = new ConcurrentMapCacheManager("customersCache");
@Mock
CustomerRepository CustomerRepository;
@InjectMocks
CustomerServiceImpl customerServiceImpl = new CustomerServiceImpl();
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testCacheForFindByCustomerName() {
Customer customer1 = new Customer();
customer1.setId("1");
customer1.setName("John");
Customer customer2 = new Customer();
customer2.setId("2");
customer2.setName("Sara");
//this should save to cache
Mockito.when(CustomerRepository.save(customer1))
.thenReturn(customer1);
customerServiceImpl.insertOrUpdate(customer1);
//Now it should retreive from cache, but not able to
Mockito.when(CustomerRepository.findByCustomerName(Mockito.any(String.class)))
.thenReturn(customer1, customer2);
Customer result = customerServiceImpl.findByCustomerName("John");
assertThat(result, is(customer1));
result = customerServiceImpl.findByCustomerName("John");
assertThat(result, is(customer1));
}
}
Exception:
I am getting an "java.lang.AssertionError:
" because the caching layer did not work and the call has been passed to repository object (twice) which has returned the 'customer2' mock object above i.e., the repository method has been invoked twice for the same key by passing the service layer.
Also, please note that I am using "Mockito" framework for my tests.
I have tried to google for unit tests on spring caching and also referred the below URL, which is almost using the same concept, but it does not work for my above code.
How to test Spring's declarative caching support on Spring Data repositories?
Could you please help to resolve the above exception ?
The Spring Cache Manager relies on Spring managing the application. You can't get that with the PowerMockRunner
, you need to use SpringJUnit4Runner
. You can still use PowerMock or Mockito programmatically, but not as a Runner.
Typically, you'll turn your unit test into a Spring-style integration test, something like this:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class SpringTest {
@Configuration
@EnableCaching
static class SpringConfig{
@Bean
public CustomerService customerService(){
return new CustomerServiceImpl(customerRepository());
}
@Bean
public CustomerRepository customerRepository(){
return Mockito.mock(CustomerRepository.class);
}
}
@Autowired
CustomerService customerService; // this will contain a proper managed cache
@Autowired
CustomerRepository customerRepository; // this is a mockito mock you can fine-tune
}