Mockito FindIterable<Document>
Mockito FindIterable<Document>
我正在尝试为以下方法编写 JUnit 测试用例,我正在使用 Mockito 框架。
方法:
public EmplInfo getMetaData(String objectId) {
objectId = new StringBuffer(objectId).reverse().toString();
try{
BasicDBObject whereClauseCondition = getMetaDataWhereClause(objectId);
EmplInfo emplinfo= new EmplInfo ();
emplinfo.set_id(objectId);
FindIterable<Document> cursorPersonDoc = personDocCollection.find(whereClauseCondition);
for (Document doc : cursorPersonDoc) {
emplinfo.setEmplFirstName(doc.getString("firstname"));
emplinfo.setEmplLastName(doc.getString("lastname"));
break;
}
return emplinfo;
}catch(Exception e){
e.printstacktrace();
}
联合:
@Test
public void testGetMetaData() throws Exception {
String docObjectId = "f2da8044b29f2e0a35c0a2b5";
BasicDBObject dbObj = personDocumentRepo.getMetaDataWhereClause(docObjectId);
FindIterable<Document> findIterable = null;
Mockito.when(collection.find(dbObj)).thenReturn(findIterable);
personDocumentRepo.getMetaData(docObjectId);
}
在 "personDocumentRepo.getMetaData(docObjectId)" 中得到空点预期,因为 "Return" findIterable 是 NULL。不确定如何将 dummy/test 值分配给 findIterable。
请指教
谢谢!
巴拉蒂
你 return null
在 collection.find(...)
模拟调用中:
FindIterable<Document> findIterable = null;
Mockito.when(collection.find(new Document())).thenReturn(findIterable);
因此模拟将在运行时 return null
。您需要的是 returning 一个 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(而使用 foreach
)。
此外,为了不去模拟 Iterator
(hasNext()
、next()
)的个别方法,这可能会使您的测试可读性降低,请使用 List
(这也是一个 Iterable
) 来填充 Document
并将模拟的 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 才会拦截并替换在 mock 上调用的方法的行为。
在运行时,参数以这种方式构建:
BasicDBObject whereClauseCondition = getMetaDataWhereClause(objectId);
EmplInfo emplinfo= new EmplInfo ();
emplinfo.set_id(objectId);
因此模拟记录中的参数应该等于上面定义的参数。
请注意,如果参数 类 的 equals()
不是 overriden/overridable,您有一些解决方法,例如:
将对象作为参数传递到要测试的方法中(需要一些重构)。在这种情况下,模拟参数和在运行时在要测试的方法中传递的引用必须相等,因为它们引用相同的对象
将给定类型的任何对象与 Mockito.any(Class<T>)
匹配。通常是最简单但不是最可靠的方法
return 使用 Answer
而不是 return 的值。那是使用 Mockito.when(...).then(Answer)
而不是 Mockito.when(...).thenReturn(valuetoReturn)
正如您正确指出的那样,您将获得 NPE,因为 FindIterable 为空。你需要嘲笑它。
模拟它并不是那么简单,因为它使用 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);
这不是一个完整的解决方案。您需要使其适应您的 class.
我想用一种模拟 DistinctIterable
(与 FindIterable
相同)的通用方法来完成 pvpkiran
回答。
NB/为了避免声纳警告,我使用内class
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();
我正在尝试为以下方法编写 JUnit 测试用例,我正在使用 Mockito 框架。
方法:
public EmplInfo getMetaData(String objectId) {
objectId = new StringBuffer(objectId).reverse().toString();
try{
BasicDBObject whereClauseCondition = getMetaDataWhereClause(objectId);
EmplInfo emplinfo= new EmplInfo ();
emplinfo.set_id(objectId);
FindIterable<Document> cursorPersonDoc = personDocCollection.find(whereClauseCondition);
for (Document doc : cursorPersonDoc) {
emplinfo.setEmplFirstName(doc.getString("firstname"));
emplinfo.setEmplLastName(doc.getString("lastname"));
break;
}
return emplinfo;
}catch(Exception e){
e.printstacktrace();
}
联合:
@Test
public void testGetMetaData() throws Exception {
String docObjectId = "f2da8044b29f2e0a35c0a2b5";
BasicDBObject dbObj = personDocumentRepo.getMetaDataWhereClause(docObjectId);
FindIterable<Document> findIterable = null;
Mockito.when(collection.find(dbObj)).thenReturn(findIterable);
personDocumentRepo.getMetaData(docObjectId);
}
在 "personDocumentRepo.getMetaData(docObjectId)" 中得到空点预期,因为 "Return" findIterable 是 NULL。不确定如何将 dummy/test 值分配给 findIterable。
请指教
谢谢! 巴拉蒂
你 return null
在 collection.find(...)
模拟调用中:
FindIterable<Document> findIterable = null;
Mockito.when(collection.find(new Document())).thenReturn(findIterable);
因此模拟将在运行时 return null
。您需要的是 returning 一个 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(而使用 foreach
)。
此外,为了不去模拟 Iterator
(hasNext()
、next()
)的个别方法,这可能会使您的测试可读性降低,请使用 List
(这也是一个 Iterable
) 来填充 Document
并将模拟的 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 才会拦截并替换在 mock 上调用的方法的行为。
在运行时,参数以这种方式构建:
BasicDBObject whereClauseCondition = getMetaDataWhereClause(objectId);
EmplInfo emplinfo= new EmplInfo ();
emplinfo.set_id(objectId);
因此模拟记录中的参数应该等于上面定义的参数。
请注意,如果参数 类 的 equals()
不是 overriden/overridable,您有一些解决方法,例如:
将对象作为参数传递到要测试的方法中(需要一些重构)。在这种情况下,模拟参数和在运行时在要测试的方法中传递的引用必须相等,因为它们引用相同的对象
将给定类型的任何对象与
Mockito.any(Class<T>)
匹配。通常是最简单但不是最可靠的方法return 使用
Answer
而不是 return 的值。那是使用Mockito.when(...).then(Answer)
而不是Mockito.when(...).thenReturn(valuetoReturn)
正如您正确指出的那样,您将获得 NPE,因为 FindIterable 为空。你需要嘲笑它。
模拟它并不是那么简单,因为它使用 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);
这不是一个完整的解决方案。您需要使其适应您的 class.
我想用一种模拟 DistinctIterable
(与 FindIterable
相同)的通用方法来完成 pvpkiran
回答。
NB/为了避免声纳警告,我使用内class
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();