2014-09-30 59 views
2

我有一个简单的方法来计算集合中的总数。分支机构的报道与foreach?

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

目标是在分支覆盖率下使用在命令行中运行的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>()); 
} 

已经使用的工具opencover,MethodToTest在分支覆盖了80%的方法之后。我的问题是,foreach循环是否会影响分支覆盖率,如果是的话,我怎样才能用这个简单的代码获得100%的分数呢?

+0

而不是编写一个foreach你不能使用集合的扩展方法'foreach'并创建一个委托? (http://msdn.microsoft.com/zh-cn/library/bwabdf9z(v = vs.110).aspx) – MethodMan 2014-09-30 21:43:41

+0

我使用其他代码覆盖工具(DotCover)运行代码示例,我有100%的代码覆盖率。难道是因为代码得到优化并且不被您的覆盖工具计算,所以不包含'sum + = value;'?在这种情况下添加一条语句'Debug.WriteLine(sum);'可能会有所帮助。 – Sjips 2014-09-30 21:49:51

+0

OpenCover查看通过编译代码生成的IL,有时编译器会添加更多的分支IL语句,因为它们可以映射到您的代码,因此它使得使用OpenCover很难获得100%的分支覆盖率。有时候团队会考虑优化一些,但并不经常(我会将其添加到候选人列表中)。 – 2014-10-01 22:36:26

回答

2

我已经更新了你的问题,使用一些linq而不是foreach循环。它需要一个随机数字(尽管相同大小的列表),所以编译器不会“扫除它”并计算它。

我会建议做一些与方法中的总和,或返回它,它可能会改变你的结果。

最后但并非最不重要的是,不要迷恋大约100%。它永远不会发生在现实生活中的大项目。只要确保你测试了可能煞车的东西,并且在测试的基础上构建你的软件,所以它很容易做到。

void Main() 
{ 
    Random r = new Random(); 
    List<int> list = Enumerable.Range(1,Int16.MaxValue) 
           .Select (e => r.Next(0,Int16.MaxValue)) 
           .ToList(); 

    // Firts attempt with a non empty collection 
    MethodToTest(new Collection<int>(list)); 

    // Second attempt with an empty collection 
    MethodToTest(new Collection<int>()); 
} 

// Define other methods and classes here 
public void MethodToTest(Collection<int> collection) 
{ 
    var sum = collection.Sum (i => i); 
    // do something with it. If you're just voiding it and it doesn't get 
    // used, it might be removed by compiler. 
} 
+0

我同意 - 编写测试来获得报道是错误的去测试和100%的分支报道通常不可能在现实生活中(如果你迷恋它,你也会发疯)。着眼于编写正确的测试和/或使用TDD实践并遵循SOLID原则,它首先看起来很辛苦,但从长远来看还是有好处的。 – 2014-10-01 22:37:01

+0

你应该已经+1了,以表示你的赞赏:) (说了这样的话,你总是很高兴看到你的统计数字......就像... 100%) – Noctis 2014-10-01 23:30:37

+0

done ...... .. :) – 2014-10-01 23:46:31

4

由于[原创]接受的答案指出你的实际情况减少了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>())); 
} 

,然后写下面的代码(注意:我们写最小值以满足当前的一组测试)

public int MethodToTest(Collection<int> collection) 
{ 
    var sum = 0; 
    return sum; 
} 

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

[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))); 
} 

如果我们跑了我们的测试中,他们将全部通过(绿色),所以我们需要一个新的测试(例)

[TestCase(new[] { 1 }, 1)] 
[TestCase(new[] { 1, 2, 3 }, 6)] 

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

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

现在我所有的测试工作,如果我跑,通过opencover我得到100%的序列和分支覆盖 - 华友世纪....我这样做不使用覆盖率作为我的控制,但编写正确的测试支持我的代码。

但有一个'可能'的缺陷......如果我通过null?需要进行新测试的时间

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

测试失败,因此我们需要更新我们的代码。

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

现在我们有支持我们的代码的测试,而不是测试我们的代码的测试,我们的测试不关心我们如何编写我们的代码。

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

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

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

我希望这会有所帮助。

+0

TTD的+1和很好的例子。当你使用'TestCase'时,你不需要你的测试在NUnit中返回吗? – Noctis 2014-10-01 23:51:32

+0

嗯...这是我写的一篇文章[单元测试](http://www.codeproject.com/Articles/784791/Introduction-to-Unit-Testing-with-MS-tests-NUnit-a)。如果你有'TestCase(...)'头的'void'方法,我得到一个:'测试被忽略:测试方法有一个void返回类型,但结果是预期的(使用nunit) – Noctis 2014-10-01 23:59:35

+0

@Noctis你可能使用了Resharper?如果是这样你需要升级,因为这是一个旧问题http://stackoverflow.com/questions/9241232/does-nunit-testcase-attribute-with-result-property-work-incorrect – 2014-10-02 01:55:53