![](/img/trans.png)
[英]What is the difference between mock() and stub() when using Mockito?
[英]What is the difference between mocking and spying when using Mockito?
使用 Mockito 間諜的用例是什么?
在我看來,每個間諜用例都可以使用 callRealMethod 進行模擬處理。
我可以看到的一個區別是,如果您希望大多數方法調用都是真實的,它會節省一些代碼行來使用模擬與間諜。 是這樣還是我錯過了更大的圖景?
答案在文檔中:
真正的部分模擬(自 1.8.0 起)
最后,經過郵件列表上的多次內部辯論和討論,Mockito 添加了部分模擬支持。 以前我們將部分模擬視為代碼異味。 但是,我們發現了部分模擬的合法用例。
在 1.8 版之前 spy() 並沒有產生真正的部分模擬,這讓一些用戶感到困惑。 閱讀有關間諜的更多信息: 此處或在 spy(Object) 方法的 javadoc 中。
callRealMethod()
是在spy()
之后引入的,但 spy() 當然留在那里,以確保向后兼容性。
否則,你是對的:間諜的所有方法都是真實的,除非被存根。 除非callRealMethod()
否則模擬的所有方法都將被存根。 一般來說,我更喜歡使用callRealMethod()
,因為它不會強迫我使用doXxx().when()
習語而不是傳統的when().thenXxx()
間諜和模擬之間的區別
當 Mockito 創建一個模擬時——它是從類型的類中創建的,而不是從實際實例中創建的。 模擬只是創建了一個類的基本外殼實例,完全用於跟蹤與它的交互。 另一方面,間諜將包裝現有的實例。 它的行為方式仍然與普通實例相同——唯一的區別是它也將被檢測以跟蹤與它的所有交互。
在下面的例子中——我們創建了一個 ArrayList 類的模擬:
@Test
public void whenCreateMock_thenCreated() {
List mockedList = Mockito.mock(ArrayList.class);
mockedList.add("one");
Mockito.verify(mockedList).add("one");
assertEquals(0, mockedList.size());
}
正如你所看到的——向模擬列表中添加一個元素實際上並沒有添加任何東西——它只是調用了沒有其他副作用的方法。 另一方面,spy 的行為會有所不同——它實際上會調用 add 方法的真正實現並將元素添加到底層列表中:
@Test
public void whenCreateSpy_thenCreate() {
List spyList = Mockito.spy(new ArrayList());
spyList.add("one");
Mockito.verify(spyList).add("one");
assertEquals(1, spyList.size());
}
在這里我們可以肯定地說調用了對象的真正內部方法,因為當你調用 size() 方法時,你得到的 size 為 1,但這個 size() 方法沒有被模擬! 那么1從哪里來? 內部真實的 size() 方法被調用,因為 size() 沒有被模擬(或存根),因此我們可以說條目被添加到真實對象中。
來源: http : //www.baeldung.com/mockito-spy + 自我筆記。
如果有一個具有 8 個方法的對象,並且您有一個測試要調用 7 個真正的方法並存根一個方法,那么您有兩個選擇:
spy
你必須通過一種方法來設置它 doCallRealMethod
的官方文檔建議使用 spy 進行部分doCallRealMethod
。
另請參閱 javadoc spy(Object) 以了解有關部分模擬的更多信息。 Mockito.spy() 是創建部分模擬的推薦方法。 原因是它保證針對正確構造的對象調用真正的方法,因為您負責構造傳遞給 spy() 方法的對象。
當您想為遺留代碼創建單元測試時,Spy 會很有用。
我在這里創建了一個可運行的例子https://www.surasint.com/mockito-with-spy/ ,我在這里復制了一些。
如果你有這樣的代碼:
public void transfer( DepositMoneyService depositMoneyService, WithdrawMoneyService withdrawMoneyService,
double amount, String fromAccount, String toAccount){
withdrawMoneyService.withdraw(fromAccount,amount);
depositMoneyService.deposit(toAccount,amount);
}
您可能不需要 spy,因為您可以模擬 DepositMoneyService 和 WithdrawMoneyService。
但是對於一些遺留代碼,依賴在代碼中是這樣的:
public void transfer(String fromAccount, String toAccount, double amount){
this.depositeMoneyService = new DepositMoneyService();
this.withdrawMoneyService = new WithdrawMoneyService();
withdrawMoneyService.withdraw(fromAccount,amount);
depositeMoneyService.deposit(toAccount,amount);
}
是的,您可以更改為第一個代碼,但隨后更改了 API。 如果這個方法被很多地方使用,你必須改變所有的地方。
另一種方法是您可以像這樣提取依賴項:
public void transfer(String fromAccount, String toAccount, double amount){
this.depositeMoneyService = proxyDepositMoneyServiceCreator();
this.withdrawMoneyService = proxyWithdrawMoneyServiceCreator();
withdrawMoneyService.withdraw(fromAccount,amount);
depositeMoneyService.deposit(toAccount,amount);
}
DepositMoneyService proxyDepositMoneyServiceCreator() {
return new DepositMoneyService();
}
WithdrawMoneyService proxyWithdrawMoneyServiceCreator() {
return new WithdrawMoneyService();
}
然后您可以使用 spy 注入依賴項,如下所示:
DepositMoneyService mockDepositMoneyService = mock(DepositMoneyService.class);
WithdrawMoneyService mockWithdrawMoneyService = mock(WithdrawMoneyService.class);
TransferMoneyService target = spy(new TransferMoneyService());
doReturn(mockDepositMoneyService)
.when(target).proxyDepositMoneyServiceCreator();
doReturn(mockWithdrawMoneyService)
.when(target).proxyWithdrawMoneyServiceCreator();
在上面的鏈接中有更多詳細信息。
Mock
vs Spy
Mock
是一個裸雙對象。 此對象具有相同的方法簽名但實現為空並返回默認值 - 0 和 null
Spy
是一個克隆的雙重對象。 新對象是基於真實對象克隆的,但您可以模擬它
class A {
String foo1() {
foo2();
return "RealString_1";
}
String foo2() {
return "RealString_2";
}
void foo3() { foo4(); }
void foo4() { }
}
@Test
public void testMockA() {
//given
A mockA = Mockito.mock(A.class);
Mockito.when(mockA.foo1()).thenReturn("MockedString");
//when
String result1 = mockA.foo1();
String result2 = mockA.foo2();
//then
assertEquals("MockedString", result1);
assertEquals(null, result2);
//Case 2
//when
mockA.foo3();
//then
verify(mockA).foo3();
verify(mockA, never()).foo4();
}
@Test
public void testSpyA() {
//given
A spyA = Mockito.spy(new A());
Mockito.when(spyA.foo1()).thenReturn("MockedString");
//when
String result1 = spyA.foo1();
String result2 = spyA.foo2();
//then
assertEquals("MockedString", result1);
assertEquals("RealString_2", result2);
//Case 2
//when
spyA.foo3();
//then
verify(spyA).foo3();
verify(spyA).foo4();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.