2011-05-01 100 views
14

單元測試中可以有循環嗎?單元測試中的循環

我的方法返回一個IEnumerable<IEnumerable>,我想單元測試這個邏輯IEnumerable<IEnumerable>創建。基本上我想測試IEnumerable中元素的計數是否與預期一致。

我找不到一個替代方法來測試內部IEnumerable沒有循環語句。請讓我知道這是不是一個好習慣。

回答

16

沒有技術上的原因,你不能這樣做。您可以在單元測試中使用多個Assert語句。在循環中使用Assert語句只是在測試中使用多個Assert語句的簡便方法。

但是,有些人認爲在單元測試中應該只有一個Assert語句。

我個人不同意 - 我認爲一個測試應該測試單一的東西 - 爲了做到這一點,有時您可能需要多個Assert語句。

如果你的方法返回商品的IEnumerable,每個產品包含Color的的IEnumerable,那麼我認爲下面的測試是爲罰款:

[Test] 
public void All_products_should_have_some_colors() 
{ 
    var products = GetProducts(); 

    foreach (var product in products) 
    { 
     Assert.IsNotEmpty(product.Colors); 
    } 
} 

但是,你需要注意的是,如果IEnumerable包含0個元素,循環將永遠不會執行任何Assert語句,並且您的單元測試將「通過」 - 而您可能會讓它失敗。

糾正這種情況,你可以有一個單獨的測試確保有在了IEnumerable大於0的元素(即的GetProducts並實際上將返回一些產品的):

Assert.IsNotEmpty(products); 
+0

感謝您的回覆。術語「可接受的」意味着以敏捷的方式做到這一點是否是一種好的做法。 – Shankar 2011-05-01 10:02:57

+2

我認爲我的答案中的測試是「可以接受的」,原因如下:1)測試「單一事物」(所有產品都有一些顏色)。 2)它簡單易讀。 – 2011-05-01 10:04:36

+0

好吧..那就是我所需要的。我問這個問題是因爲有人說我們在每個測試中只需要一個Assert,所以我想從他們那裏知道我們如何去測試這個方法:) – Shankar 2011-05-01 10:06:46

8

一個原因,以避免書寫測試中的一個循環就是讓測試一目瞭然,簡潔易讀。由於您使用NUnit標記了問題,並且您說您只是想測試元素數量是否與預期的一樣,請考慮使用NUnit Constraints進行聲明。

例如,

IEnumerable<IEnumerable<char>> someStrings = new[] { "abc", "cat", "bit", "hat" }; 

Assert.That(someStrings, Has.All.With.Length.EqualTo(3).And.All.Contains("a")); 

失敗消息:

預期:至3的所有項目屬性長度相等且含有 「一」 所有項目字符串,但是:< 「ABC」, 「貓」,「位」,「帽子」>

但通過如果您更改「位」爲「蝙蝠」。

這本書的xUnit測試模式:重構測試代碼 傑拉德梅薩羅斯

有許多問題的答案,如你的。

+0

+1,用於暗示使用NUnit約束,但是我建議您可能想要將長度和「包含」約束拆分爲單獨的測試或至少單獨的斷言。 – 2017-08-10 17:40:52

2

是的,你可以在單元測試中有循環,但要謹慎。如Alex York所述,如果您測試一個的東西,循環是可以接受的;即一個期望。

如果你使用的循環,那麼我建議你必須做兩件事情:

  1. 如上所述,測試一個非空迭代集。迭代空集是誤報。假陽性結果是所有自動化測試的禍根,因爲沒有人會雙重檢查綠色結果。
  2. 包含描述當前迭代的測試描述。至少包括迭代指數。

這是我測試一個對象的大於屬性的例子。

[Test] 
public void TestCompare_XtoY_GreaterThan() 
{ 
    int numObjects = mOrderedList.Count; 
    for (int i = 1; i < numObjects; ++i) 
    { 
    for (int j = 0; j < i; ++j) 
    { 
     string testDescription = string.Format("{0} is greater than {1} which implies\n {2}\n is greater than\n {3}" 
              , i, j 
              , mOrderedList[i], mOrderedList[j] 
              ); 
     Assert.IsTrue(0 < mOrderedList[i].CompareTo(mOrderedList[j]), testDescription); 
     Assert.IsTrue(0 < mOrderedList[i].Compare(mOrderedList[i], mOrderedList[j]), testDescription); 
     Assert.IsTrue(0 < mOrderedList[j].Compare(mOrderedList[i], mOrderedList[j]), testDescription); 
     Assert.Greater(mOrderedList[i], mOrderedList[j], testDescription); 
    } 
    } 
} 

我測試我的有序列表使用的測試設置非空:

[SetUp] 
public void GeneralTestSetup() 
{ 
    // verify the iterated sources are not empty 
    string testDescription = string.Format("The ordered list of objects must have at least 3 elements, but instead has only {0}.", mOrderedList.Count); 
    Assert.IsTrue(2 < mOrderedList.Count, testDescription); 
} 

我有多個斷言,即使在我的循環,但所有的斷言測試的單一預期:

if i > j then mOrderedList[i] > mOrderedList[j] 

在迭代級別的測試說明是等你拿故障,如:

10 is greater than 9 which implies 
    TestActionMethodInfo: [Actions.File, Version=1.0.446.0, File, VerifyReadOnly] 
    is greater than 
    TestActionMethodInfo: [Actions.File, Version=1.0.446.0, File, Write] 
Expected: True 
But was: False 

,而不只是:

Expected: True 
But was: False 

約我上面的代碼問題/爭論:

是我在測試一個東西嗎?

我對對象內的4種不同比較方法斷言,這可能會被認爲是測試4件事情之一。計數器大於大於大於,並且所有進行評估的方法應該一致。