简体   繁体   中英

Mock Hibernate entityManager with createQuery(), parameters and executeUpdate()

I'm new on Unit Testing in java; I've an application that uses Hibernate to interact with a MySQL database.

I have many queries built with createQuery() method, also with parameters, like the following one:

return this.entityManager.createQuery("from MyEntity m where param  = :param", MyEntity.class)
    .setParameter("param", param)
    .getSingleResult();

I would like to avoid to mock all the subsequent calls on the entityManager object, because sometimes I've query with more than 5 parameters and seems not that handy to mock each of those calls.

The same concept can be applied on Builder objects .

Edit 1

I add a concrete example of what I use (given that it's not a good way to manage exception, but unluckly is quiet usual):

public class MyService {
private EntityManager entityManager;

public MyEntity find(String field ) {
        try{
            return this.entityManager.createQuery("from MyEntity  c where c.field = :field ", MyEntity .class)
                    .setParameter("field ", field )
                    .getSingleResult();
        } catch (NoResultException e) {
            return null;
        } catch (NonUniqueResultException e) {
            logger.error("find", e);
            return null;
        }
    }
}

In this example, given the behavior of the call on entityManager I have different branches to be tested. Then I have to mock the answer of that call to test all the lines of this method.

What I found

What I found was the following:

@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private EntityManager entityManager;

Which works as expected. I can mock all the calls' chain. BUT

  1. Citing from the Javadoc of Mockito.RETURNS_DEEP_STUBS :

WARNING: This feature should rarely be required for regular clean code. Leave it for legacy code, Mocking a mock to return a mock, to return a mock. (..,). to return something meaningful hints at violation of Law of Demeter or mocking a value object (a well known anti-pattern).

  1. If the previous point wasn't enough, the next one, some lines after, clearly set a big limitation:

This feature will not work when any return type of methods included in the chain cannot be mocked (for example: is a primitive or a final class). This is because of java type system.

The second point means that if I try to mock in this way the method executeUpdate() , which returns an int , it raise an exception.

when(entityManager.createQuery(anyString())
                .setParameter(eq("param"), anyString())
                .executeUpdate())
.thenReturn(1);

and in that way I can't test the interactions with the entityManager .

Questions

  1. How should I mock the calls on entityManager ? It seems impossible to me that I have to mock each method one by one.
  2. Is wrong to use Answers.RETURNS_DEEP_STUBS ? If not, how can I handle the second example?

Don't mock the JPA API, just write integration tests with proper test data and execute the real queries against real data to see if everything works. Projects like testcontainers make it very easy to get started.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM