2009-11-11 64 views
17

我曾經寫過NUnit測試的代碼。但是,我從來沒有用過嘲笑框架。他們是什麼?我理解依賴注入以及它如何幫助提高可測試性。我的意思是所有的依賴可以在單元測試時被模擬。但是,那麼爲什麼我們需要嘲笑框架呢?我們不能簡單地創建模擬對象並提供依賴關係。我在這裏錯過了什麼嗎? 謝謝。爲什麼我們需要嘲笑框架?

回答

12
  • 它使嘲弄更容易
  • 他們通常 讓你表達可測試 斷言參考對象之間的互動 。

這裏有一個例子:

var extension = MockRepository 
    .GenerateMock<IContextExtension<StandardContext>>(); 
    var ctx = new StandardContext(); 
    ctx.AddExtension(extension); 
    extension.AssertWasCalled(
    e=>e.Attach(null), 
    o=>o.Constraints(Is.Equal(ctx))); 

你可以看到,我明確地測試該IContextExtension的連接方法被調用,並且據說上下文對象的輸入參數。如果沒有發生,這會使我的測試失敗。

2

使用嘲諷庫的唯一原因是它使嘲笑更容易。

當然,你可以在沒有圖書館的情況下做到這一切,如果它很簡單,那很好,但只要它們開始變得複雜,圖書館就容易得多。

想到這個排序算法,確定任何人都可以寫一個,但爲什麼?如果代碼已經存在並且很容易調用...爲什麼不使用它?

+2

有些嘲諷框架不僅僅是手工完成,嘲笑靜態。 – 2009-11-14 19:03:21

11

您可以手動創建模擬對象,並在使用依賴注入框架進行測試時使用它們,但讓模擬框架爲您生成模擬對象可節省時間。

一如既往,如果使用該框架增加了太多的複雜性,那麼請不要使用它。

1

你當然可以手動嘲弄你的依賴關係,但是對於一個框架來說,它需要花費很多繁瑣的工作。此外,通常可用的斷言使其值得學習。

3

使用一個模擬框架可以是一個更輕量級和簡單的解決方案來提供模擬,而不是爲每個想要模擬的對象創建一個模擬對象。

例如,模擬框架對驗證呼叫是否已完成(甚至是進行了多少次呼叫)等事情特別有用。製作你自己的模擬對象來檢查這樣的行爲(嘲笑行爲本身就是一個主題)是單調乏味的,而且還有一個地方可以引入一個bug。

查看Rhino Mocks瞭解嘲笑框架的強大程度。

7

有時,在使用第三方庫或者甚至使用.NET框架的某些方面時,在某些情況下編寫測試非常困難 - 例如,HttpContext或Sharepoint對象。爲這些創建模擬對象可能會變得非常麻煩,所以嘲笑框架會關注基礎知識,以便我們花時間專注於使我們的應用程序具有獨特性的原因。

3

模擬對象代替您的代碼需要訪問才能運行的任何大型/複雜/外部對象。

他們是有幾個原因是有益的:

  • 你的測試是爲了快速,輕鬆地運行。如果你的代碼依賴於數據庫連接,那麼你需要運行一個完全配置和填充的數據庫才能運行你的測試。這可能會讓人討厭,所以你創建一個替換 - 一個「模擬」 - 數據庫連接對象,只是模擬數據庫。

  • 您可以準確控制來自Mock對象的輸出,因此可以將它們用作可控數據源來進行測試。

  • 您可以在之前創建模擬,然後創建實際對象以優化其界面。這在測試驅動開發中很有用。

0

好嘲諷框架使我的生活變得更輕鬆,少繁瑣,所以我可以把時間花在實際編寫代碼。如果你有MyComplex.class然後有一個模擬框架的價值就不言而喻了更換List.class就拿的Mockito(在Java世界中)

//mock creation 
List mockedList = mock(List.class); 

//using mock object 
mockedList.add("one"); 
mockedList.clear(); 

//verification 
verify(mockedList).add("one"); 
verify(mockedList).clear(); 

//stubbing using built-in anyInt() argument matcher 
when(mockedList.get(anyInt())).thenReturn("element"); 

//stubbing using hamcrest (let's say isValid() returns your own hamcrest matcher): 
when(mockedList.contains(argThat(isValid()))).thenReturn("element"); 

//following prints "element" 
System.out.println(mockedList.get(999)); 

雖然這是一個人爲的例子。你可以自己寫或不寫,但爲什麼你想要走這條路。

0

我首先想到了爲什麼我需要一個模擬框架,當我比較手動編寫單元測試集(每個測試需要稍微不同的行爲,因此我爲每個測試創建基類假類型的子類)使用像RhinoMocks或Moq這樣的工具來完成相同的工作。

簡單地說,使用框架生成所需的所有假對象比手動編寫(並調試)我自己的假貨要快得多。

1

模擬框架允許您從代碼的依賴關係中隔離要測試的代碼單元。它們還允許您在測試環境中模擬代碼依賴項的各種行爲,否則可能難以設置或複製。

例如,如果我有一個包含我想測試的業務規則和邏輯的類A,但這個類A依賴於數據訪問類,其他業務類,甚至是u/i類等,則這些其他類類可以被嘲笑以某種方式執行(或者在鬆散的模擬行爲的情況下根本沒有任何方式)來基於這些其他類在生產環境中可以想象的行爲的每種可想象的方式來測試A類中的邏輯。

舉一個更深的例子,假設你的類A調用方法對數據訪問類如

public bool IsOrderOnHold(int orderNumber) {} 

然後將數據訪問類的模擬可以設置每一個時間或返回true每次都返回false,以測試你的A類如何迴應這種情況。

+0

好說。模擬允許行爲被重寫。 – j2emanue 2015-04-22 15:54:13

1

我聲稱你沒有。編寫測試雙打併不是一件很麻煩的事情,在10次的9次之內。大部分時間它幾乎完全是通過請求resharper爲你實現一個接口自動完成的,然後你只需添加這個double所需的小細節(因爲你沒有做一堆邏輯和創造這些錯綜複雜的超級測試雙打,對吧?)

「但是爲什麼我想讓我的測試項目臃腫一堆測試雙打?」你可能會問。那麼你不應該。 DRY原則也適用於測試。創建可重複使用並具有描述性名稱的良好測試雙打。這使您的測試更具可讀性。

有一件事更難做的是過度使用測試雙打。我傾向於同意Roy Osherove和Bob叔叔,你真的不想用一些特殊的配置創建一個模擬對象。這本身就是一種設計氣味。使用一個框架,在幾乎每個測試中都可以使用複雜的邏輯來使用測試雙打,並且最終你會發現你並沒有真正測試過你的生產代碼,但你只是測試了神奇的弗蘭肯斯坦的一系列含有模擬嘲笑更多的嘲笑。如果你寫自己的雙打,你永遠不會「意外地」做到這一點。

當然,有人會指出有時候你「有」使用框架,而不是這樣做會是愚蠢的。當然,有這種情況。但你可能沒有這種情況。大多數人不會,只有一小部分代碼或代碼本身非常糟糕。

我推薦任何人(特別是初學者)遠離框架,學習如何在沒有框架的情況下學習,然後當他們覺得他們真的必須使用他們認爲最合適的框架時,但到那時它將成爲一個明智的解決方案,他們將不太可能濫用框架來創建錯誤的代碼。