Home > Mobile >  How to mock a variable and method in Abstract Class?
How to mock a variable and method in Abstract Class?

Time:05-18

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 :)

  • Related