You return null
in collection.find(...)
mocked invocation :
FindIterable<Document> findIterable = null;
Mockito.when(collection.find(new Document())).thenReturn(findIterable);
So the mock will return null
at runtime. What you need is returning a FindIterable<Document>
object that allows to execute the code to test associated to :
for (Document doc : cursorPersonDoc) {
emplinfo.setEmplFirstName(doc.getString("firstname"));
emplinfo.setEmplLastName(doc.getString("lastname"));
break;
}
return emplinfo;
In this way you can assert that the method does what it is designed to :
setting the first name and the last name from the retrieved FindIterable<Document>
.
You could use the Mockito.mock()
method to mock FindIterable<Document>
that is an Iterable (whereas the used foreach
).
Additionally, to not bother to mock individual methods of Iterator
(hasNext()
, next()
) that could make you test less readable, use a List
(that is also an Iterable
) to populate the Document
s and delegate the behavior of the mocked FindIterable.iterator()
to List.iterator()
.
@Test
public void testGetMetaData() throws Exception {
...
// add your document instances
final List<Document> documentsMocked = new ArrayList<>();
documentsMocked.add(new Document(...));
documentsMocked.add(new Document(...));
// mock FindIterable<Document>
FindIterable<Document> findIterableMocked = (FindIterable<Document>) Mockito.mock(FindIterable.class);
// mock the behavior of FindIterable.iterator() by delegating to List.iterator()
when(findIterableMocked.iterator()).thenReturn(documentsMocked.iterator());
// record a behavior for Collection.find()
Mockito.when(collection.find(dbObj)).thenReturn(findIterableMocked);
// execute your method to test
EmplInfo actualEmplInfo = personDocumentRepo.getMetaData(...);
// assert that actualEmplInfo has the expected state
Assert(...);
}
I would add that such a mock will probably not work :
Mockito.when(collection.find(new Document())).thenReturn(findIterable);
Mockito will intercept and replace the behavior of the method invoked on the mock only if the arguments in the recording match (in terms of equals()
) with the arguments passed at runtime by the tested method.
At runtime, the argument is build in this way :
BasicDBObject whereClauseCondition = getMetaDataWhereClause(objectId);
EmplInfo emplinfo= new EmplInfo ();
emplinfo.set_id(objectId);
So the argument in the mock recording should be equal to which one defined above.
Note that if equals()
is not overriden/overridable for the arguments classes, you have some workarounds such as :
passing the object as argument in the method to test (require some refactoring). In this case, Mocked argument and the referenced passed at runtime in the method to test are necessarily equal as these refer the same object
matching any object of given type with Mockito.any(Class<T>)
. Often the simplest way but not the most robust
returning an Answer
instead of the value to return. That is using Mockito.when(...).then(Answer)
instead of Mockito.when(...).thenReturn(valuetoReturn)
personDocumentRepo
in your test class. Where is that coming from? And what is the point of settingfindIterable()
to null? Also note: you don't understand whatwhen().thenReturn()
is doing. There is no point in passingnew Document()
for a mocking spec. Instead, you want to pass a matcher, likewhen(any())
to indicate that you don't are what gets passed. But then: when you want to return null on any parameter, then you dont need a spec at all. Because that is what mockito does by default. Long story short: – Parathion