2013-07-02 48 views
3

可以使用模擬對象或不使用模擬對象來測試方法。我喜歡的解決方案,而模擬的時候都沒有必要的,因爲:用模擬還是不用模擬測試更好?

  1. 他們使測試更加難以理解。
  2. 重構後,修復junit測試是否很痛苦,如果它們是通過模擬實現的。

但是我想問你的意見。

public class OndemandBuilder { 

    .... 
    private LinksBuilder linksBuilder;  
    .... 

    public OndemandBuilder buildLink(String pid) { 

     broadcastOfBuilder = new LinksBuilder(pipsBeanFactory); 
     broadcastOfBuilder.type(XXX).pid(pid); 
     return this; 

    } 

測試與嘲笑:這裏測試方法

@Test 
public void testbuildLink() throws Exception { 

    String type = "XXX"; 
    String pid = "test_pid"; 

    LinksBuilder linkBuilder = mock(LinksBuilder.class); 
    given(linkBuilder.type(type)).willReturn(linkBuilder); 

    //builderFactory replace the new call in order to mock it 
    given(builderFactory.createLinksBuilder(pipsBeanFactory)).willReturn(linkBuilder); 

    OndemandBuilder returnedBuilder = builder.buildLink(pid); 

    assertEquals(builder, returnedBuilder); //they point to the same obj 
    verify(linkBuilder, times(1)).type(type); 
    verify(linkBuilder, times(1)).pid(pid); 
    verifyNoMoreInteractions(linkBuilder); 
} 

方法中的returnedBuilder OBJ buildLink是「這個」這意味着,因爲它們指向建設者和returnedBuilder不能是不同的內存中的相同對象,所以assertEquals並不真正測試它是否包含由buildLink方法(這是pid)設置的期望字段。

我已經改變了測試,如下所示,不使用模擬。下面的測試聲明我們要測試的是哪個構建器包含的LinkBuilder不爲null,並且LinkBuilder pid是預期的。

@Test 
public void testbuildLink() throws Exception { 
    String pid = "test_pid"; 

    OndemandBuilder returnedBuilder = builder.buildLink(pid); 

    assertNotNull(returnedBuilder.getLinkBuilder()); 
    assertEquals(pid, returnedBuilder.getLinkBuilder().getPid()); 
} 

我不會用假除非他們是必要的,但我不知道這是有道理,還是我誤解了測試的模擬方式。

回答

0

這一切都取決於您通過UNIT測試瞭解的內容。

因爲當你試圖單元測試一個類時,這意味着你並不擔心底層系統/接口。你假設他們工作正常,因此你只是嘲笑他們。當我說你是ASSUMING意味着你單獨測試底層接口。

因此,當你在沒有模擬的情況下編寫你的JUnits時,你基本上正在進行一個系統或一個集成測試。

但是要回答你的問題,兩種方式都有其優點/缺點,理想情況下系統應該都有。

1

在編寫單元測試時,在一個堅果殼中你有類之間的依賴關係,並且你想測試一個依賴另一個類的類時,Mocking是一個非常強大的工具,你可以使用模擬對象來限制測試的範圍以便您只測試要測試的類中的代碼,而不測試它依賴的那些類。我沒有進一步解釋,我強烈建議您閱讀輝煌的Martin Fowler作品Mocks Aren't Stubs,以獲得有關該主題的完整介紹。

在你的例子中,沒有模擬的測試絕對是更清晰的,但你會注意到你的測試在OndemandBuilderLinksBuilder這兩個類中都有代碼。這可能是你想要做的,但是這裏的'問題'是,如果測試失敗了,這可能是由於這兩個類中的任何一個的問題。在你的情況下,因爲OndemandBuilder.buildLink中的代碼是最小的,我會說你的方法是好的。但是,如果此函數中的邏輯更加複雜,那麼我建議您想要以不依賴於LinksBuilder.type方法的行爲的方式對此方法進行單元測試。這是模擬對象可以幫助你的地方。

假設我們想要測試OndemandBuilder.buildLink獨立於LinksBuilder實施。爲此,我們希望能夠用模擬對象替換中的linksBuilder對象 - 通過這樣做,我們可以精確地控制調用此模擬對象返回的內容,從而打破對LinksBuilder實現的依賴。這是該技術Dependency Injection可以幫助您 - 下面的例子展示了我們如何可以修改OndemandBuilder允許linksBuilder與模擬對象來代替(通過注射在構造函數依賴):現在

public class OndemandBuilder { 

    .... 
    private LinksBuilder linksBuilder;  
    .... 

    public class OndemandBuilder(LinksBuilder linksBuilder) { 
     this.linksBuilder = linksBuilder; 
    } 

    public OndemandBuilder buildLink(String pid) { 

     broadcastOfBuilder = new LinksBuilder(pipsBeanFactory); 
     broadcastOfBuilder.type(XXX).pid(pid); 
     return this; 

    } 
} 

,在測試,當您創建OndemandBuilder對象時,可以創建LinksBuilder的模擬版本,將其傳遞給構造函數,並控制它的行爲如何用於測試。通過使用模擬對象和依賴注入,您現在可以正確地單獨測試OndemandBuilder,而不受LinksBuilder實現的影響。

希望這會有所幫助。