2010-03-06 64 views
8

实例类伪代码:如何测试或描述无尽的可能性?

class SumCalculator 
    method calculate(int1, int2) returns int 

什么是测试这是一个好办法吗?换句话说,我应该如何描述我需要的行为?

test1: canDetermineSumOfTwoIntegers 

test2: returnsSumOfTwoIntegers 

test3: knowsFivePlusThreeIsEight 

的Test1和Test2的似乎含糊不清,那就需要测试特定的计算,所以它并没有真正描述的是被测试。然而test3非常有限。

什么是测试这些类的好方法?

回答

10

我将测试的边界条件(最大-INT,分钟-INT,零,正,负)和一些典型的情况:

test1: sumOfPosAndPos 
test2: sumOfPosAndNeg 
test3: sumOfPosAndZero 
test4: sumOfNegAndZero 
test5: sumOfMaxIntAndMinInt 

+1

可能会添加sumOfMaxIntAndMaxInt并检查报告失败的函数。这是我能想到的最边界的情况。 – pmr 2010-03-06 15:51:32

+0

sumOfMaxIntAndOne也应该导致异常,不是吗?这将是另一个好的边缘案例。 否则我同意。试想一下几个可能会有所不同的可能性,然后去解决这个问题。 – 2010-03-07 20:48:15

+1

不要忘记负面测试用例 test6:sumOfStringAndPositive(应该引发异常或返回错误) – 2010-03-08 15:57:44

5

有几种哲学。 Roy Osherove,作者The Art of Unit Testing,似乎是prefer using explicit values,并选择每个Equivalence Class的最低(或最简单)表示。

该原理并不适用于您的示例,但在许多其他场景中运行得非常好。

例如,如果一个类需要输入一个正整数,那么选择数字,因为它是所有正整数的最简单表示。

个人而言,我更喜欢一个原则,我叫Constrained Non-Determinism。这里的关键是我们让某种工厂为我们提供给定类型的匿名变量,因为它迫使我们直接在测试中建立关系。

我使用AutoFixture做到这一点(但你也可以用别的东西),所以在这种情况下,我会测试这样的SumCalculator:

var fixture = new Fixture(); 
var int1 = fixture.CreateAnonymous<int>(); 
var int2 = fixture.CreateAnonymous<int>(); 
var expectedResult = int1 + int2; 
var sut = fixture.CreateAnonymous<SumCalculator>(); 

var result = sut.Calculate(int1, int2); 

Assert.AreEqual(expectedResult, result); 

原则上,这种单一的测试提供了一个计算方法的规格。我们永远不知道int1int2的值是多少,而且在所有那些实际上并不重要的情况下,这是非常合适的。

3

如果你正在测试数学函数,我建议你应该对它的反函数进行测试,例如:对于做x = a + b的函数,你应该测试ax = -b和xb = a ,这仅仅是为了说明,当然它不适用于每一种情况。

1

此处的另一种替代方法是使用Parameterized Test Case删除测试中的复制。基本上,一个表包含测试的所有数据,以元组形式([term1,term2,sum]),然后一个测试用例在表上迭代以调用参数化测试用例来测试表中的一行:

I也会增加负数(这里溢出)测试:什么是calculate(MAXINT, 1)应该返回?

1

查看David Saff在理论测试方面的工作; here (PDF)就是一个例子。这基本上是一种断言,某些集合(包括所有可能值的集合)中的某些东西(如函数是其函数的逆函数)是真实的 - 并将该断言表达为测试。您可以通过随机选择的值运行测试(如果集合太大而无法彻底运行),并将故障自动记录为特定的具体回归测试,可以做一些有趣的事情。