4 回答

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);
這不是一個完整的解決方案。您需要使其適應您的班級。

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)

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();
添加回答
舉報