Reputation: 433
Mockito's JavaDocs on verify
methods link to this interesting article about asking and telling. I'm a bit lost there specially with the "stubbed interactions are verified implicitly".
Let's take an example:
Imagine a have this class
class FooDao {
private EntityManager entityManager;
public FooDao(EntityManager entityManager) {
this.entityManager = entityManager;
}
public List<Foo> findFooByName(String name, String otherParam) {
String hql = "SELECT f FROM Foo f WHERE 1 = 1 ";
if(name != null) {
hql += " AND f.name = :name";
}
if(otherParam != null) {
hql += " AND f.other = :otherParam";
}
TypedQuery<Foo> query = this.entityManager.createQuery(hql, Foo.class);
if(name != null) {
query.setParameter("name", name);
}
if(otherParam != null) {
query.setParameter("otherParam", otherParam);
}
return query.getResultList();
}
}
Now, let's see what can I check about this method:
First of all I will mock the EntityManager
object because I don't want to access a real database.
@InjectMocks
private FooDao dao;
@Mock
private EntityManager entityManager;
Now, I could just add something like this:
@Mock
private TypedQuery<Foo> mockQuery;
@Test
public void testFindFooByName() {
List<Foo> stubData = stubData(); // Method definition omitted for brevity
// Return the custom mockedQuery with the entityManager
Mockito.when(mockQuery.getResultList()).thenReturn(stubData);
Mockito.when(entityManager.createQuery(Mockito.anyString(),
Mockito.eq(Foo.class)))
.thenReturn(mockQuery);
List<Foo> actual = dao.findFooByName("foobar", null);
// Now what should I check?
}
So, now the question is what to check. I could just add an assertEquals(stubData, actual)
and the test would succeed.
I could also add:
Mockito.verify(entityManager).createQuery(expectedSql, Foo.class);
Mockito.verify(mockQuery).setParameter("name", "foobar");
The first verification will ensure that the HQL query has been constructed properly and the second one will ensure that the parameter was correctly bound to the query. Are these verifications necessary at all or just asserting the result is enough?
Upvotes: 4
Views: 5913
Reputation: 47945
You have to stub the interaction with entityManager
since otherwise your test would cause a NPE to be thrown when findFooByName()
invokes setParameter()
or getQueryList()
The choice about whether to stub or verify the query.getResultList()
call comes down to how specific you want your test to be ...
Least Specific
The following test is non specific about how the TypedQuery
is created and instead satisfies itself that it is somehow created and that its getResultList()
method is invoked.
@Test
public void testFindFooByName() {
List<Foo> stubData = stubData();
Mockito.when(entityManager.createQuery(Mockito.anyString(), Mockito.eq(Foo.class))).thenReturn(mockQuery);
dao.findFooByName("foobar", null);
Mockito.verify(mockQuery).getResultList();
}
More Specific
The following test is non specific about how the TypedQuery
is created and instead verifies that it is somehow created and that the result of its getResultList()
call is returned by the method-under-test.
@Test
public void testFindFooByName() {
List<Foo> stubData = stubData();
Mockito.when(mockQuery.getResultList()).thenReturn(stubData);
Mockito.when(entityManager.createQuery(Mockito.anyString(), Mockito.eq(Foo.class))).thenReturn(mockQuery);
List<Foo> actual = dao.findFooByName("foobar", null);
Assert.assertSame(stubData, actual);
}
Most Specific
The following test proves all of the following (from your OP):
That the result is what I expect.
That the parameters are correctly bound to the query object.
That the HQL query is constructed properly for the parameters given.
@Test
public void testFindFooByName() {
String name = "foobar";
String otherParam = "otherParam";
String expectedHql = "SELECT f FROM Foo f WHERE 1 = 1 AND f.name = :name AND f.other = :otherParam";
List<Foo> stubData = stubData();
Mockito.when(mockQuery.getResultList()).thenReturn(stubData);
Mockito.when(entityManager.createQuery(Mockito.eq(expectedHql), Mockito.eq(Foo.class))).thenReturn(mockQuery);
List<Foo> actual = dao.findFooByName(name, otherParam);
Assert.assertSame(stubData, actual);
Mockito.verify(mockQuery).setParameter("name", name);
Mockito.verify(mockQuery).setParameter("otherParam", otherParam);
}
So, in summary, when determining whether to include verifications or stubbed interactions or both you likely want to consider:
Upvotes: 3