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
- 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).
- 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
- How should I mock the calls on
entityManager? It seems impossible to me that I have to mock each method one by one. - Is wrong to use
Answers.RETURNS_DEEP_STUBS? If not, how can I handle the second example?