2012-09-27 131 views
1

我有一個關於單元測試的基本問題。我在代碼中發現了一個崩潰,並且我編寫了一個測試來重現該錯誤。然後,我修復了這個錯誤並確認它通過了測試。我的問題是,如果我採取了最好的方法。下面是一個簡化的例子:單元測試:是否有效進行最小化測試?

public class ClassC 
{ 
    private int internalFlag; 

    void all(Dependency dep1, Dependency dep2, Dependency dep3, Dependency dep4) 
    { 
     a(dep1); 
     b(dep2) 
     c(dep3) 
     d(dep4) 
     e(); 
     f(); 
    } 

    void e() 
    { 
     if (some logic based on dep3) 
     { 
      internalFlag = 2; 
     } 
    } 

    void f() 
    { 
     if (internalFlag == 2) 
     { 
      Log("All is well"); 
     } 
     else 
     { 
      Log("Crash occurs") 
     } 
    } 
} 

在上面的例子中,我有一個名爲 「所有」 的方法調用方法A,B,C,d,E,F。現在,我在「f」中發現了一個崩潰,因爲「internalVar」不是預期的值。這個'internalVar'被設置爲「e」,但是正如你所看到的,如果條件爲假,那麼「e」不會將internalFalg設置爲任何東西,所以這個錯誤發生在e。

我能夠編寫測試。隔離錯誤然後,我固定的bug,並發現測試過去那是偉大的,但爲了做到這一點,我不得不這樣做。

void testAll() 
{ 
    mockDep1 = mock(dep1); 
    mockDep2 = mock(dep2); 
    mockDep3 = mock(dep3); 
    mockDep4 = mock(dep4); 

    all(mockDep1, mockDep2, mockDep3, mockDep4); 
} 

現在,我讓mockDep1..4部分很簡單,在這裏在這個例子中,但它實際上是很長的艱苦代碼我的問題是,它是有效的,而不是僅僅做最小的調用重現崩潰:

void testCrash() 
{ 
    mockDep3 = mock(dep3); 
    c(mockDep3)  
    e() 
    f(); 
} 

這將是我將被要求做的重現和測試崩潰,除非它不完全如何在實際的方法「all」中調用每個方法的代碼。它看起來像編寫testAll上面包括所有的嘲笑一遍又一遍每個bug是有點泰迪。但是,再次,那是如何實際的方法「全部」將工作。因此,如果全面的方法被調用,即使隔離不完全如何工作,它是否更好地隔離錯誤?

回答

0

從你的例子中不清楚的是哪些方法是公開的,哪些是私有的(或者是保護的或者包私有的)。如果唯一的公共方法是all,那麼只要有可能,這就是您的測試應該調用的方法,除非您正在測試真正包含在其中一種方法中的複雜邏輯。

當您選擇要編寫哪些測試時,您應該真正關注此類合同的內容。您的應用程序的其他應用程序期望此類提供哪些功能?將您的測試方法建立在功能上;而不是你碰巧編寫了哪些方法。此外,如果Dependency類的唯一目的是支持ClassC的功能,那麼你可以考慮編寫將SUT與ClassC和Dependency結合在一起的測試(有些人會稱之爲「集成測試」,有些人會稱它們爲「集成測試」 「單元測試,單元由兩個類組成」)。

在你的特殊情況下,你的類似乎提供了跨越整個分區運行的功能。因此,測試功能 - 並測試可能導致功能以不同方式工作的不同情況。不要測試個別方法。特別是,您將有多種測試在各種情況下調用all方法;其中一些會導致錯誤發生(至少在修復錯誤之前),而其中一些則不會。

最後,爲了幫助您根據測試功能和場景進行思考,我相信您應該根據正在執行的功能和場景命名您的測試方法,而不是通過所調用的方法命名。特別是,我認爲testAll(實際上,任何由test組成的名稱後跟一個方法的名稱)對於測試方法來說是一個很差的名字。但也許這是另一天需要思考的問題。

+0

我想我明白你在說什麼,但也許我不喜歡答案。我猜你是在說我必須對「全部」進行一些調用,提供不同的模擬來觸發不同的路徑,一個產生崩潰。我想我發現爲每次測試重複構建所有這些模擬以避免崩潰,當我可以直接調用e()和f()來觸發崩潰並測試修復時,會有點乏味。但在這種情況下,你是對的,e()和f()應該是私有的,所以這不是一個選項。這似乎是一種困難的測試方式。 – SpecialEd

+0

我通常使用[Mockito註釋](http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#9)來創建我的嘲笑,這樣我就不必重新編輯它,爲每個測試編碼它們。如果所有模擬都需要特定的存根,我通常會在具有JUnit'@ Before'標籤的方法中進行設置。 –

+0

我也使用Mockito,雖然我是新手。當你說「註釋」或只是提到像mock()doAnswer()等典型的mockito命令時,你的意思是什麼?我認爲你是對的,也許我可以簡化我的測試,如果我利用了「設置」方法,我認爲它類似於你提到的@Before標記。 – SpecialEd

相關問題