unit-test search method (querydsl) with mockito

31 Views Asked by At

In my springboot app I'm trying to write a unit test for my search method using mockito:

Service:

QRental qRental = QRental.rental;
        var jpaQuery = new JPAQuery<Rental>(entityManager)
                .select(qRental)
                .from(qRental);


        if (reason != null && !reason.isBlank()) {
            jpaQuery = jpaQuery.where(qRental.reason.likeIgnoreCase(reason));
        }

        var result = jpaQuery.fetch();
        return rentalMapper.toDtos(result);

Test:

@ExtendWith(MockitoExtension.class)
class RentalServiceImplTest {

    
    @Mock
    private JPAQuery<Rental> jpaQuery;


    @Mock
    private EntityManager entityManager;

    @Mock
    private QRental qRental;

    @InjectMocks
    private RentalServiceImpl rentalService;

    @Test
    void searchRentals() {


        when(jpaQuery.select()).thenReturn(new JPAQuery<>());
        when(jpaQuery.from()).thenReturn(new JPAQuery<>());
        when(jpaQuery.where()).thenReturn(new JPAQuery<>());

do more stuff...

And i get this error:

java.lang.NullPointerException: Cannot invoke "javax.persistence.EntityManagerFactory.getProperties()" because the return value of "javax.persistence.EntityManager.getEntityManagerFactory()" is null

    at com.querydsl.jpa.impl.JPAProvider.getTemplates(JPAProvider.java:94)
    at com.querydsl.jpa.impl.JPAQuery.<init>(JPAQuery.java:48)

I think the problem has to do with the EntityManager initialization, but Im not 100% sure. Can anyone help??? If more info is required, I'm happy to provide :) Thanks in advance!!!

I want to mock querydsl used in RentalServiceImpl, in order for it to return a predefined list of rental entities for the test.

1

There are 1 best solutions below

0
Lesiak On

Firstly, mocking DB API is not an effective approach to testing DB queries.

  • you rely heavily on DB Access library internals
  • you are not likely to find any syntax errors

Instead, you should:

  • configure your tests to start up a DB on your machine. Ideally, use same engine that you use on PROD.
  • This can be embedded DB, or run in Docker
  • You can fall back to H2, which is the quickest to set up, but differences from your PROD engine will eventually bite you.
  • Use Spring-Boots DataJpaTest to test your Data Access component against this DB
  • Note that DataJpaTest uses H2 by default, configure your test to disable this behaviour

For testing your service methods, mocking entire repository component is a good approach.

And for your original question:

Look at the implementation of JPAProvider.getTemplates

// detect by properties
for (String key : em.getEntityManagerFactory().getProperties().keySet()) {
    key = key.toLowerCase();
    for (Map.Entry<String, JPQLTemplates> entry : templatesByName.entrySet()) {
        if (key.contains(entry.getKey())) {
            return entry.getValue();
        }
    }
}

Most likely hou are missing a stub for one of methods in em.getEntityManagerFactory().getProperties().keySet() chain, thus Mockito returns default value, which is null.