4 回答
![?](http://img1.sycdn.imooc.com/533e4d00000171e602000200-100-100.jpg)
TA贡献1809条经验 获得超8个赞
正如您正确指出的那样,您将获得NPE,因为FindIterable为null。您需要模拟它。模拟
它并不是那么简单,因为它使用MongoCursor(又扩展了Iterator),因此您需要模拟内部使用的某些方法。
在遍历Iter的某些方法时
我相信你必须做这样的事情。
FindIterable iterable = mock(FindIterable.class);
MongoCursor cursor = mock(MongoCursor.class);
Document doc1= //create dummy document;
Document doc2= //create dummy document;
when(collection.find(dbObj)).thenReturn(iterable);
when(iterable.iterator()).thenReturn(cursor);
when(cursor.hasNext())
.thenReturn(true)
.thenReturn(true)// do this as many times as you want your loop to traverse
.thenReturn(false); // Make sure you return false at the end.
when(cursor.next())
.thenReturn(doc1)
.thenReturn(doc2);
这不是一个完整的解决方案。您需要使其适应您的班级。
![?](http://img1.sycdn.imooc.com/5333a1bc00014e8302000200-100-100.jpg)
TA贡献1827条经验 获得超9个赞
您将返回null在collection.find(...)嘲笑调用:
FindIterable<Document> findIterable = null;
Mockito.when(collection.find(new Document())).thenReturn(findIterable);
因此,该模拟将null在运行时返回。您需要返回一个FindIterable<Document>对象,该对象允许执行代码以测试与关联的对象:
for (Document doc : cursorPersonDoc) {
emplinfo.setEmplFirstName(doc.getString("firstname"));
emplinfo.setEmplLastName(doc.getString("lastname"));
break;
}
return emplinfo;
这样,您可以断言该方法已实现其设计目的:设置检索到的名字和姓氏FindIterable<Document>。
您可以使用该Mockito.mock()方法来模拟FindIterable<Document>一个Iterable(而used foreach)。
此外,为了不打扰嘲笑的各个方法Iterator(hasNext(),next()),可以使你少测试可读,使用List(这也是一个Iterable)来填充DocumentS和委托嘲笑的行为FindIterable.iterator()来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(...);
}
我要补充一点,这样的模拟可能不会起作用:
Mockito.when(collection.find(new Document())).thenReturn(findIterable);
仅当记录中的参数(以表示equals())与运行时通过测试的方法传递的参数匹配时,Mockito才会拦截并替换在模拟程序上调用的方法的行为。
在运行时,以这种方式构建参数:
BasicDBObject whereClauseCondition = getMetaDataWhereClause(objectId);
EmplInfo emplinfo= new EmplInfo ();
emplinfo.set_id(objectId);
因此,模拟录制中的自变量应等于上面定义的自变量。
请注意,如果equals()参数类不能被覆盖/覆盖,则可以采用以下解决方法:
将对象作为参数传递给方法进行测试(需要进行一些重构)。在这种情况下,模拟参数和运行时在测试方法中传递的引用必须相等,因为它们引用相同的对象
将任何给定类型的对象与匹配Mockito.any(Class<T>)。通常是最简单的方法,但不是最可靠的
返回Answer而不是要返回的值。那是用Mockito.when(...).then(Answer)代替Mockito.when(...).thenReturn(valuetoReturn)
![?](http://img1.sycdn.imooc.com/533e52b90001456f02000200-100-100.jpg)
TA贡献1806条经验 获得超8个赞
我想pvpkiran用一种通用的方法来模拟DistinctIterable(与FindIterable)来完成答案。
注意:为了避免声纳警告,我使用内部类
private DistinctIterable<String> mockDistinctIterableString(List<String> resultList) {
DistinctIterable<String> iterable = mock(DistinctIterableString.class);
MongoCursor cursor = mock(MongoCursor.class);
doReturn(cursor)
.when(iterable).iterator();
OngoingStubbing<Boolean> whenHasNext = when(cursor.hasNext());
for (String resultEntry : resultList) {
whenHasNext = whenHasNext.thenReturn(true);
}
whenHasNext.thenReturn(false);
if (CollectionUtils.isEmpty(resultList)) {
return iterable;
}
OngoingStubbing<Object> whenNext = when(cursor.next());
for (String resultEntry : resultList) {
whenNext = whenNext.thenReturn(resultEntry);
}
return iterable;
}
public interface DistinctIterableString extends com.mongodb.client.DistinctIterable<String> {
}
用:
doReturn(mockDistinctIterableString(asList(
"entry1",
"entry2",
"lastEntry"
)))
.when(myRepository)
.myMongoDistinctQuery();
添加回答
举报