給定一個需要使用特定服務的單元測驗類,似乎有不同的方法來偽造服務的行為,例如使用模擬框架或實作存根類。
例如,讀取/寫入磁盤的服務:
public interface FileServiceInterface {
public void write(String text);
public String read(String fileName);
}
我可能有一個偽造其行為的類,然后在測驗類中使用它,注入 Stub 而不是真正的實作:
public class FileServiceStub implements FileServiceInterface {
ConcurrentHashMap<String, String> content = new ConcurrentHashMap<>();
public void write(String fileName, String text) {
content.put(fileName, text);
}
public String read(String fileName) {
return content.get(fileName);
}
}
其他選項是讓 Mockito(例如)直接在測驗類中攔截對服務的呼叫:
public class TestExample {
@Mock
private FileServiceImpl service; // A real implementation of the service
@Test
void doSomeReadTesting() {
when(service.read(any(String.class))).thenReturn("something");
...
}
}
我想知道這些替代方案中的哪一個是最好的(或目前最被接受的)方法,以及是否有任何其他/更好的選擇。謝謝。
uj5u.com熱心網友回復:
簡短的回答:取決于用例,當您需要檢查行為時使用Mock,否則在基于狀態的測驗的情況下使用Stub。
在狀態驗證中,您讓被測物件在提供所有必要的存根后執行特定操作。當它結束時,您檢查物件的狀態并驗證它是預期的狀態。
在行為驗證中,您準確指定要呼叫哪些方法,因此驗證的不是結束狀態是否正確,而是執行的步驟順序是否正確。
Martin Fowler 在 Mocks Aren't Stubs 文章中描述了Stubs和Mocks之間的一個很好的比較。
出于測驗目的,有幾種型別的假想物件代替真實物件:
- 虛擬物件被傳遞但從未實際使用過。通常它們僅用于填充引數串列。
- 假物件實際上有作業實作,但通常采取一些捷徑,這使得它們不適合生產(記憶體資料庫就是一個很好的例子)。
- 存根為測驗期間撥打的電話提供預設答案,通常根本不回應任何超出測驗程式的內容。
- 間諜是存根,它還根據呼叫方式記錄一些資訊。其中一種形式可能是電子郵件服務,它記錄發送了多少訊息。
- 模擬預編程的物件,這些期望形成了他們期望接收的呼叫的規范。
在您的情況下,我們有Fake vs Mock物件型別。它們看起來都像真實物件,但與Mocks不同,其他型別沒有預編程的期望,可能會導致您的測驗失敗。Stub或Fake只關心最終狀態 - 而不是該狀態是如何派生的
。
所以我們有兩種不同的設計風格的測驗。
基于狀態的測驗更加黑盒化。他們實際上并不關心被測系統(SUT)如何實作其結果,只要它是正確的。這使它們更能抵抗變化并且與設計的耦合更少。
但是偶爾你會遇到一些很難使用狀態驗證的事情,即使它們不是尷尬的合作。一個很好的例子就是快取。快取的全部意義在于,您無法從其狀態中判斷快取是否命中或未命中——在這種情況下,行為驗證將是一個明智的選擇。
Mock的另一個好處是能夠定義對期望的寬松約束 - 你可以使用any(), anyString(), withAnyArguments(). 它是靈活的。
模擬和存根有什么區別?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/468150.html
