以您的示例(经过一些重构)为例,
assert(a + b, math.add(a, b));
无助于:
- 了解
math.add
内部行为如何,
- 知道边缘情况会发生什么。
几乎等于说:
- 如果您想知道该方法的作用,请亲自查看数百行源代码(因为是的,
math.add
可以包含数百个LOC;请参见下文)。
- 我不介意该方法是否正常工作。如果期望值和实际值都与我真正期望的值不同,则可以。
这也意味着您不必添加以下测试:
assert(3, math.add(1, 2));
assert(4, math.add(2, 2));
它们无济于事,或者至少在您提出第一个断言之后,第二个就没什么用。
相反,该怎么办:
const numeric Pi = 3.1415926535897932384626433832795;
const numeric Expected = 4.1415926535897932384626433832795;
assert(Expected, math.add(Pi, 1),
"Adding an integer to a long numeric doesn't give a long numeric result.");
assert(Expected, math.add(1, Pi),
"Adding a long numeric to an integer doesn't give a long numeric result.");
这是不言而喻的,对您和以后将维护源代码的人都非常有用。想象一下,这个人对做了一点修改,math.add
以简化代码并优化性能,然后看到如下测试结果:
Test TestNumeric() failed on assertion 2, line 5: Adding a long numeric to an
integer doesn't give a long numeric result.
Expected value: 4.1415926535897932384626433832795
Actual value: 4
该人员将立即了解到,新修改的方法取决于参数的顺序:如果第一个参数是整数,第二个参数是长整数,则结果将是整数,而预期是长整数。
以同样的方式,4.141592
在第一个断言中获取的实际值是不言自明的:您知道该方法具有很高的精度,但是实际上,它失败了。
出于相同的原因,在某些语言中,以下两个断言可能有意义:
// We don't expect a concatenation. `math` library is not intended for this.
assert(0, math.add("Hello", "World"));
// We expect the method to convert every string as if it was a decimal.
assert(5, math.add("0x2F", 5));
另外,关于:
assert(numeric.Infinity, math.add(numeric.Infinity, 1));
也是不言自明的:您希望您的方法能够正确处理无穷大。去超越无限或抛出异常不是预期的行为。
或者,也许取决于您的语言,这会更有意义吗?
/**
* Ensures that when adding numbers which exceed the maximum value, the method
* fails with OverflowException, instead of restarting at numeric.Minimum + 1.
*/
TestOverflow()
{
UnitTest.ExpectException(ofType(OverflowException));
numeric result = math.add(numeric.Maximum, 1));
UnitTest.Fail("The tested code succeeded, while an OverflowException was
expected.");
}
How does unit testing work?
没人真正知道:)