In a Java (Spring Boot) app, I use JUnit and Mockito and want to test the following service method:
public Page<EmployeeDTO> findAll(EmployeeRequest request, final Sort sort) {
final List<EmployeeDTO> list = getDTOList(request);
// code omitted for brevity
}
The getDTOList
method is in the following abstract class:
public abstract class CustomCriteriaQueries {
private EntityManager entityManager;
protected void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
protected List<D> getDTOList(EmployeeRequest request) {
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
// code omitted
return entityManager
.createQuery(cq)
.stream()
.collect(Collectors.toList());
}
}
I tried to mock EntityManager
using @Mock
and stub via mockito.when().then()
, but as far as I see, it cannot be mocked as in concrete classes. So, how should I mock the variables and methods in abstract class?
CodePudding user response:
In my opinion use Mockito.when(CustomCriteriaQueries.class), then mock any method that you need to use.
@Test
public void testMethod(){
CustomCriteriaQueries customCriteriaQueries = Mockito.when(CustomCriteriaQueries.class);
Assert.anyOperationYouNeed(customCriteriaQueries.getDTOList(this.buildEmployeeRequest));
}
CodePudding user response:
You can't test an abstract class directly but in order to test a particular implementation you will need to mock it anyway.
Just reduce the testing code duplicates and there you go:
public abstract class AbstractService<T extends Serializable, R extends AbstractResource<T>> {
protected final Logger log;
protected final R resource;
protected AbstractService(Logger log, R resource) {
this.log = log;
this.resource = resource;
}
public T findEntity(Long id) {
log.debug("Loading an entity by ID={}", id);
return resource.findEntity(id);
}
}
The concrete implementation:
public class NinjaService extends AbstractService<Ninja, NinjaResource> {
// the bonus service
private final KatanaService katanaService;
@Autowired
public NinjaService(Logger log, NinjaResource ninjaResource, KatanaService katanaService) {
super(log, ninjaResource);
this.katanaService = katanaService;
}
}
So, the test layer would look like this:
public abstract class AbstractServiceTester<T extends Serializable, R extends AbstractResource<T>, D extends AbstractService<T, R>> {
@MockBean
protected R resource;
@Autowired
protected D service;
protected void mockFindEntityMethod(Long id, T expected) {
// the mocking logics
}
}
The implementation test:
@SpringBootTest
public class NinjaTester extends AbstractServiceTester<Ninja, NinjaResource, NinjaService> {
@MockBean
private KatanaService katanaService;
@Test
public void shouldLoadNinja() {
Ninja ninja = new Ninja(1L, "Test");
mockFindEntityMethod(ninja.getId(), ninja);
assertEquals(ninja, service.findEntity(ninja.getId()));
}
...
}
That's it :)