用foreach覆盖分支?

oxm*_*man 3 c# asp.net visual-studio-2010 opencover

我有一个简单的方法可以计算集合中的总数。

public void MethodToTest(Collection<int> collection)
{
    int sum = 0;
    foreach (int value in collection)
    {
        sum += value;
    }
}
Run Code Online (Sandbox Code Playgroud)

目标是使用在命令行中运行的opencoverage工具获得100%的分支覆盖率。我还得到了一个调用方法MethodToTest的单元测试:

[TestMethod]
public void TestMethodToTest()
{
    BomProviderMock mock = new BomProviderMock();
    BomManager bomManager = new BomManager(mock);

    List<int> list = new List<int>();
    for (int i = 0; i <= Int16.MaxValue; i++)
    {
        list.Add(i);
    }
    // Firts attempt with a non empty collection
    bomManager.MethodToTest(new Collection<int>(list));

    // Second attempt with an empty collection
    bomManager.MethodToTest(new Collection<int>());
}
Run Code Online (Sandbox Code Playgroud)

使用工具opencover之后,MethodToTest方法的分支覆盖率达到80%。我的问题是,foreach循环是否会影响分支覆盖率,如果是,那么如何使用此简单代码获得100%的收益?

Sha*_*lde 5

正如[原始]接受的答案指出,您的实际情况减少到 collection.Sum()但是您将无法每次都摆脱掉。

如果我们使用TDD来开发此功能(我同意但容易解释的过大杀伤力),我们将[可能]执行以下操作(在本示例中,我也不希望使用NUnit)

[Test]
public void Sum_Is_Zero_When_No_Entries()
{
    var bomManager = new BomManager();
    Assert.AreEqual(0, bomManager.MethodToTest(new Collection<int>()));
}
Run Code Online (Sandbox Code Playgroud)

然后编写以下代码(注意:我们编写满足当前测试集的最低要求)

public int MethodToTest(Collection<int> collection)
{
    var sum = 0;
    return sum;
}
Run Code Online (Sandbox Code Playgroud)

然后,我们将编写一个新的测试,例如

[Test]
[TestCase(new[] { 0 }, 0)]
public void Sum_Is_Calculated_Correctly_When_Entries_Supplied(int[] data, int expected)
{
    var bomManager = new BomManager();
    Assert.AreEqual(expected, bomManager.MethodToTest(new Collection<int>(data)));
}
Run Code Online (Sandbox Code Playgroud)

如果我们运行测试,它们都将通过(绿色),因此我们需要一个新的测试(案例)

[TestCase(new[] { 1 }, 1)]
[TestCase(new[] { 1, 2, 3 }, 6)]
Run Code Online (Sandbox Code Playgroud)

为了满足那些测试,我需要修改我的代码,例如

public int MethodToTest(Collection<int> collection)
{
    var sum = 0;
    foreach (var value in collection)
    {
        sum += value;
    }
    return sum;
}
Run Code Online (Sandbox Code Playgroud)

现在我所有的测试工作正常,并且如果我通过opencover运行该测试,我将获得100%的序列和分支覆盖率-Hurrah!....我这样做的时候没有使用覆盖率作为控件,而是编写了正确的测试来支持我的代码。

但是有一个“可能的”缺陷……如果我通过了该null怎么办?是时候进行新的测试了

[Test]
public void Sum_Is_Zero_When_Null_Collection()
{
    var bomManager = new BomManager();
    Assert.AreEqual(0, bomManager.MethodToTest(null));
}
Run Code Online (Sandbox Code Playgroud)

测试失败,因此我们需要更新代码,例如

public int MethodToTest(Collection<int> collection)
{
    var sum = 0;
    if (collection != null)
    {
        foreach (var value in collection)
        {
            sum += value;
        }
    }
    return sum;
}
Run Code Online (Sandbox Code Playgroud)

现在,我们有支持代码的测试,而不是支持代码的测试,即我们的测试不在乎编写代码的方式。

现在我们有一组很好的测试,因此我们现在可以安全地重构代码,例如

public int MethodToTest(IEnumerable<int> collection)
{
    return (collection ?? new int[0]).Sum();
}
Run Code Online (Sandbox Code Playgroud)

我这样做并没有影响任何现有测试。

我希望这有帮助。