僞造,嘲笑和存根之間有什麼區別?

我知道我如何使用這些術語,可是我想知道是否存在接受僞造模擬存根的單元測試定義? 您如何爲測試定義這些? 描述您可能會使用每種狀況的狀況。 html

這是個人用法: 編程

Fake :實現接口但包含固定數據且沒有邏輯的類。 只需根據實現返回「好」或「壞」數據。 框架

Mock :一個實現接口並容許動態設置要返回的值/從特定方法拋出異常的類,並提供檢查是否已調用/未調用特定方法的能力。 單元測試

存根(Stub) :相似於模擬類,不一樣之處在於它不提供驗證方法是否已被調用的能力。 學習

模擬和存根能夠手動生成,也能夠由模擬框架生成。 僞類是手工生成的。 我主要使用模擬來驗證個人類和依賴類之間的交互。 一旦驗證了交互做用並測試了代碼中的替代路徑,便會使用存根。 我主要使用僞造的類來抽象出數據依賴性,或者當模擬/存根過於繁瑣而沒法每次設置時。 測試


#1樓

讓我感到驚訝的是,這個問題已經存在了很長時間,並且尚未人根據Roy Osherove的「單元測試的藝術」給出答案。 spa

在「 3.1介紹存根」中,將存根定義爲: 設計

存根是系統中現有依賴項(或協做者)的可控替代。 經過使用存根,您能夠測試代碼而無需直接處理依賴項。 日誌

並將存根和模擬之間的區別定義爲: code

關於模擬與存根之間要記住的主要事情是,模擬就像存根同樣,可是您針對模擬對象斷言,而您不針對存根進行斷言。

虛假只是存根和模擬的名稱。 例如,當您不關心存根和模擬之間的區別時。

Osherove區分存根和模擬的方式,意味着用做測試僞造品的任何類均可以是存根或模擬。 特定測試的內容徹底取決於您如何在測試中編寫檢查。

  • 當您的測試檢查被測類中的值或除僞造品以外的其餘任何地方時,僞造品被用做存根。 它只是提供了供被測類使用的值,能夠直接經過調用返回的值來提供,也能夠經過調用致使的反作用(在某些狀態下)來間接提供。
  • 當您的測試檢查僞造品的值時,它被用做模擬。

使用FakeX類做爲存根的測試示例:

const pleaseReturn5 = 5;
var fake = new FakeX(pleaseReturn5);
var cut = new ClassUnderTest(fake);

cut.SquareIt;

Assert.AreEqual(25, cut.SomeProperty);

fake實例用做存根,由於Assert根本不使用fake

使用測試類X做爲模擬的測試示例:

const pleaseReturn5 = 5;
var fake = new FakeX(pleaseReturn5);
var cut = new ClassUnderTest(fake);

cut.SquareIt;

Assert.AreEqual(25, fake.SomeProperty);

在這種狀況下, Assert檢查fake的值,使該假成爲模擬。

如今,這些示例固然是很是人爲設計的,可是我認爲這種區別很是有價值。 它使您知道如何測試本身的東西以及測試的依賴關係在哪裏。

我贊成Osherove的觀點

從純粹的可維護性角度來看,在個人測試中,使用模擬比不使用模擬會帶來更多的麻煩。 那是個人經驗,可是我一直在學習新的東西。

斷言是您真正要避免的事情,由於它使您的測試高度依賴於徹底不是被測類的類的實現。 這意味着類ActualClassUnderTest的測試能夠開始中斷,由於ClassUsedAsMock的實現ClassUsedAsMock更改。 那給我散發出難聞的氣味。 用於測試ActualClassUnderTest時最好只有突破ActualClassUnderTest改變。

我意識到寫斷言是對僞造的一種慣例,尤爲是當您是TDD訂戶的嘲笑者類型時。 我想我與馬丁·福勒(Martin Fowler)在古典主義陣營中堅決不移(請參閱馬丁·福勒Martin Fowler)的「模仿不是存根」 (Ockserove not not Stubs )),而且像Osherove同樣,儘量避免進行交互測試(只能經過斷言來進行測試)。

有趣的閱​​讀,爲何你應該避免在這裏定義的模擬,谷歌爲「福勒模擬古典主義者」。 您會發現不少意見。


#2樓

您能夠得到一些信息:

馬丁·福勒(Martin Fowler)着《模擬與存根》

對象實際上具備有效的實現,可是一般採起一些捷徑,這使它們不適合生產

存根提供對測試過程當中進行的呼叫的固定答覆,一般一般根本不響應爲測試編程的內容。 存根還能夠記錄有關呼叫的信息,例如,電子郵件網關存根能夠記住「已發送」的消息,或者僅記住「已發送」的消息數量。

嘲諷是咱們在這裏談論的:帶有指望的預編程對象,這些對象造成了指望接收的呼叫的規範。

xunitpattern

僞造的 :咱們獲取或構建一種很是輕量級的功能,實現與SUT依賴的組件所提供的功能相同的功能,並指示SUT使用它而不是真實的。

存根(Stub) :此實現被配置爲使用將執行SUT中未經測試的代碼(請參閱第X頁的生產錯誤)的值(或異常)響應來自SUT的調用。 使用測試存根的一個關鍵指示是因爲沒法控制SUT的間接輸入而致使未測試代碼

模擬對象 ,實現與SUT(被測系統)所依賴的對象相同的接口。 當咱們須要進行行爲驗證時,能夠將模擬對象用做觀察點,以免因沒法觀察調用方法對SUT的反作用而致使未經測試的需求(請參閱第X頁的生產錯誤)。

親身

我嘗試經過使用簡化:模擬和存根。 當它是一個返回設置爲測試類的值的對象時,我會使用Mock。 我使用Stub模仿要測試的Interface或Abstract類。 實際上,您所說的並不重要,它們都是生產中不使用的類,而且用做測試的實用程序類。


#3樓

若是您熟悉Arrange-Act-Assert,那麼解釋存根和模擬之間的差別可能對您有用的一種方法是,存根屬於安排部分,由於它們是用於排列輸入狀態的,而模擬屬於斷言部分,由於它們用於斷言結果。

假人什麼也沒作。 它們僅用於填充參數列表,所以不會出現未定義或空錯誤。 它們也能夠知足嚴格類型化語言中的類型檢查器的要求,所以能夠容許您編譯和運行它們。


#4樓

爲了說明存根和模擬的用法,我還要列舉一個基於Roy Osherove的「 單元測試的藝術 」的示例。

想象一下,咱們有一個LogAnalyzer應用程序,它具備打印日誌的惟一功能。 它不只須要與Web服務對話,並且若是Web服務引起錯誤,則LogAnalyzer必須將錯誤記錄到其餘外部依賴項中,並經過電子郵件將其發送給Web服務管理員。

這是咱們要在LogAnalyzer中測試的邏輯:

if(fileName.Length<8)
{
 try
  {
    service.LogError("Filename too short:" + fileName);
  }
 catch (Exception e)
  {
    email.SendEmail("a","subject",e.Message);
  }
}

當Web服務引起異常時,如何測試LogAnalyzer正確調用電子郵件服務? 這是咱們面臨的問題:

  • 咱們如何替換Web服務?

  • 咱們如何模擬來自Web服務的異常,以便咱們能夠測試對電子郵件服務的呼叫?

  • 咱們如何知道電子郵件服務被正確調用或徹底被調用?

經過使用Web服務的存根,咱們能夠處理前兩個問題。 爲了解決第三個問題,咱們能夠將模擬對象用於電子郵件服務

假貨是一個通用術語,能夠用來描述存根或模擬。在咱們的測試中,咱們將有兩個假貨。 一種將是電子郵件服務模擬,咱們將使用它來驗證是否已將正確的參數發送到電子郵件服務。 另外一個將是一個存根,咱們將使用它來模擬從Web服務引起的異常。 這是一個存根,由於咱們不會使用僞造的Web服務來驗證測試結果,只是爲了確保測試正確運行。 電子郵件服務是一個模擬,由於咱們會斷言它已被正確調用。

[TestFixture]
public class LogAnalyzer2Tests
{
[Test]
 public void Analyze_WebServiceThrows_SendsEmail()
 {
   StubService stubService = new StubService();
   stubService.ToThrow= new Exception("fake exception");
   MockEmailService mockEmail = new MockEmailService();

   LogAnalyzer2 log = new LogAnalyzer2();
   log.Service = stubService
   log.Email=mockEmail;
   string tooShortFileName="abc.ext";
   log.Analyze(tooShortFileName);

   Assert.AreEqual("a",mockEmail.To); //MOCKING USED
   Assert.AreEqual("fake exception",mockEmail.Body); //MOCKING USED
   Assert.AreEqual("subject",mockEmail.Subject);
 }
}

#5樓

您在其中聲明的東西稱爲模擬對象,而其餘僅有助於測試運行的東西都是存根

相關文章
相關標籤/搜索