单元测试我认为如何将逻辑错误指向正在测试的类
本文关键字:测试 错误 单元测试 | 更新日期: 2023-09-27 18:22:14
我正在阅读《单元测试的艺术》一书,并试图理解基于状态的测试逻辑。在一个主题的例子中,有一个类似的计算器类
public class Calculator
{
private int sum=0;
public void Add(int number)
{
sum+=number;
}
public int Sum()
{
int temp = sum;
sum = 0;
return temp;
}
}
这本书展示了我们如何将其测试为:
[TestFixture]
public class CalculatorTests
{
private Calculator calc;
[SetUp]
public void Setup()
{
calc = new Calculator();
}
[Test]
public void Sum_NoAddCalls_DefaultsToZero()
{
int lastSum = calc.Sum();
Assert.AreEqual(0,lastSum);
}
[Test]
public void Add_CalledOnce_SavesNumberForSum()
{
calc.Add(1);
int lastSum = calc.Sum();
Assert.AreEqual(1,lastSum);
}
[Test]
public void Sum_AfterCall_ResetsToZero()
{
calc.Add(1);
calc.Sum();
int lastSum = calc.Sum();
Assert.AreEqual(0, lastSum);
}
}
所以在这之前,一切都很好,但是,比方说,我正在写一个计算器类和那个类一样多,并且我制作了类似的方法
public int Sum()
{
return sum;
}
和
测试类,如
[TestFixture]
public class CalculatorTests
{
private Calculator calc;
[SetUp]
public void Setup()
{
calc = new Calculator();
}
[Test]
public void Sum_NoAddCalls_DefaultsToZero()
{
int lastSum = calc.Sum();
Assert.AreEqual(0,lastSum);
}
[Test]
public void Add_CalledOnce_SavesNumberForSum()
{
calc.Add(1);
int lastSum = calc.Sum();
Assert.AreEqual(1,lastSum);
}
}
比方说,我没有很好地意识到,当我写代码时,当我为此写单元测试时,我是如何发现下面的错误的?因为错误是在2加法之后总和不会为零,就像下面的过程一样
add(1)
add(23)
sum() is 24 now
add(11)
add(12)
sum() => will be 47 but it has to be 23.
那么,当我写单元测试的时候,我是怎么想得到那个逻辑错误的呢。(如果我写它,NUnit会告诉我有一个错误)然后我回来,会看到要点,我会改变计算器类,比如
public int Sum()
{
int temp = sum;
sum = 0;
return temp;
}
我希望你能理解我想说的话
谢谢
基本上你不能确定地找到所有的边缘情况。但是,您可以指定代码要做什么,并编写干净的代码。如果计算器在要求求和后应该重置其和,那么这是应该进行测试的"规范"的一部分,这是某人发明的"要求",所以写测试应该很容易记住。
更困难的是通过编码的方式创建的所有边缘情况。我过去常常参加编码面试,为候选人编写代码单元测试。我以为我有一套很好的测试来证明某些东西有效。但我很快发现,人们可以通过引入难以测试的边缘案例的方式来编写代码(比如某个东西在第9次失败时,它做了一些似乎每次都应该有效的事情)。因此,主要的是,如果你遵循TDD的建议,编写测试,编写代码以使其通过,重构以使代码干净,你就不会错得太多。
记住,这不是一个神奇的子弹,这不是一些神奇的公式,可以让你写完美的代码。你仍然需要思考,思考你在做什么。
听起来你基本上已经有了一个测试用例:
[Test]
public void CallingSumResets()
{
var calc = new Calculator();
calc.Add(10);
Assert.AreEqual(10, calc.Sum());
Assert.AreEqual(0, calc.Sum());
}
它实际执行添加的测试将在其他测试中完成——这只是测试在您第一次调用Sum
后,它会重置内部状态。
此测试应失败:
[Test]
public void Sum_AfterCall_ResetsToZero()
{
calc.Add(1);
calc.Sum();
int lastSum = calc.Sum();
Assert.AreEqual(0, lastSum);
}
直到您更改代码以在调用Sum()
后重置总和。但是,我更愿意创建一个单独的方法Clear()
,而不是在getter中重置总和。
TDD步骤
- 想想你想让计算器做什么
- 为它写一个测试
- 写入通过测试的代码
如果我理解正确,下面的示例代码就是您的实现,并且有一个bug;它不会像正确的实现那样将和值重置为零,从而产生错误。你的问题是,如何为此编写单元测试?
public int Sum()
{
return sum;
}
假设我正确解释了你的问题,你应该简单地编写一个测试,在第二次调用时检测值是否为零:
add(11)
add(12)
sum() => ignore result
sum() => Should be zero