2010-06-29 22 views
2

這個寫作維護單元測試是一類的簡化版本,我正在寫與模仿對象

class SomeClass { 

    void methodA() { 
     methodB(); 
     methodC(); 
     methodD(); 
    } 

    void methodB() { 
     //does something 
    } 

    void methodC() { 
     //does something 
    } 

    void methodD() { 
     //does something 
    } 
} 

單元測試在寫這個類的單元測試,我已經使用了EasyMock嘲笑了對象用於每種方法。設置模擬對象和它們的期望很容易 在方法B,C和D中。但是爲了測試方法A,我必須設置更多模擬對象及其期望。另外,我在不同的條件下測試方法A,這意味着我必須以不同的期望多次設置模擬對象。

最後,我的單元測試變得很難維護和非常混亂。我想知道是否有人或已經看到這個問題很好的解決方案。

回答

3

如果我正確理解你的問題,我認爲這是一個設計問題。單元測試的好處在於寫作測試通常會迫使您更好地設計您的設計。如果您在測試方法時需要嘲笑太多東西,那麼通常意味着您應該將您的類分成兩個較小的類,這將更容易測試(以及編寫和維護以及錯誤修復和重用等)。

在你的情況,該方法的似乎是比方法的一個更高的水平,B,C。你可以認爲這是消除向更高層次類,將包裹SomeClass的:

class HigherLevelClass { 
    ISomeClass someClass; 

    public HigherLevelClass(ISomeClass someClass) 
    { 
     this.someClass = someClass; 
    } 

    void methodA() { 
     someClass.methodB(); 
     someClass.methodC(); 
     someClass.methodD(); 
    } 
} 

class SomeClass : ISomeClass { 
    void methodB() { 
     //does something 
    } 

    void methodC() { 
     //does something 
    } 

    void methodD() { 
     //does something 
    } 
} 

現在當你正在測試methodA所需要的只是一個小的ISomeClass接口和三個方法調用。

+0

+1好回答你的類的情況。 – mickthompson 2010-06-30 12:08:43

0

您可以將常用設置代碼提取到單獨的(可能參數化的)方法中,然後在適當時調用它們。如果methodA的測試與其他方法的測試有很大不同,那麼可能沒有太多東西放入@Before方法本身,因此您需要從測試方法本身調用適當的設置幫助器方法組合。它仍然有點繁瑣,但比遍佈整個地方的代碼複製要好得多。

根據您使用的單元測試框架,也可能有其他選項,但上述應該適用於任何框架。

0

這是Fragile test的一個示例,因爲模擬設置對SUT有太深入的瞭解。

我不知道EasyMock,但是用Moq你不需要設置void方法。但是,通過Moq,這些方法必須是公開的或者是保護性的,並且是虛擬的。

0

對於您正在編寫的每個測試,請考慮對該測試有價值的行爲。您將設置一些您要建立的行爲所依賴的上下文,以及您想要驗證的行爲的結果。

設置相關上下文,驗證結果,並將NiceMocks用於其他任何事情。

我更喜歡默認使用這種方式的Mockito(Java)或Moq(.NET)。下面是的Mockito對頁面的Mockito EasyMock的對比,所以你可以明白我的意思(EasyMock的沒有NiceMock沿的Mockito出現之前):

http://code.google.com/p/mockito/wiki/MockitoVSEasyMock

你或許可以以類似的方式使用了EasyMock的NiceMock。希望這會幫助你解開你的測試。您可以隨時導入這兩個框架,並將它們並排使用/如果有幫助,可以逐漸切換。

祝你好運!

0

我在不同的條件下測試方法A,這意味着我必須用不同的期望多次設置模擬對象。

如果你關心什麼方法正在做什麼,以及哪個協作者函數必須被調用,那麼你必須設置不同的期望......我看不到你如何跳過這一步?

如果您使用testLogout,則會希望調用myCollaborator.logout(),否則如果您使用testLogin,則會期望類似myCollaborator.login()的內容。

如果你有大量的/不同的期望很多方法也許就是分裂的合作者