我有一个简单的方法来计算集合中的总数。
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 :(得分: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>()));
}
然后编写以下代码(注意:我们编写最小值以满足当前的测试集)
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%的序列和分支覆盖 - Hurray!....我没有使用coverage作为我的控件,但编写正确的测试以支持我的代码。
但是有可能的&#39;缺陷...如果我通过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();
}
我这样做并没有影响任何现有的测试。
我希望这会有所帮助。
答案 1 :(得分: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.
}