2011-05-01 99 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件事情之一。计数器大于大于大于,并且所有进行评估的方法应该一致。