问题
Example class in pseudocode:
class SumCalculator
method calculate(int1, int2) returns int
What is a good way to test this? In other words how should I describe the behavior I need?
test1: canDetermineSumOfTwoIntegers
or
test2: returnsSumOfTwoIntegers
or
test3: knowsFivePlusThreeIsEight
Test1 and Test2 seem vague and it would need to test a specific calculation, so it doesn't really describe what is being tested. Yet test3 is very limited.
What is a good way to test such classes?
回答1:
I would test the boundary conditions (max-int, min-int, zero, positive, negative) and some typical cases:
test1: sumOfPosAndPos
test2: sumOfPosAndNeg
test3: sumOfPosAndZero
test4: sumOfNegAndZero
test5: sumOfMaxIntAndMinInt
etc.
回答2:
There are several philosophies. Roy Osherove, author of The Art of Unit Testing, seems to prefer using explicit values, and selecting the lowest (or simplest) representation of each Equivalence Class.
That principle doesn't apply itself particularly well to your example, but works really well in many other scenarios.
If, for example, a class requires an input of a positive integer, you pick the number 1 because it's the simplest representation of all positive intergers.
Personally, I rather prefer a principle I call Constrained Non-Determinism. The point here is that we let some kind of factory serve us anonymous variables for the given type, because it forces us to establish the relationship directly in the test.
I'm using AutoFixture to do this (but you could also use something else), so in this case I would test the SumCalculator like this:
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);
In principle, this single test provides a specification for the Calculate method. We never know what the values of int1
and int2
are, and that is very appropriate in all those many cases where it actually doesn't matter.
回答3:
if you're testing mathematical function, i would suggest you should test it against its inverse function, for example: for function that do x = a + b, you should test it whether a-x = -b and x-b = a, this is just for illustration, ofcourse it won't work on every case.
回答4:
Another alternative here would be to used a Parameterized Test Case to remove the duplication in the tests. Basically a table contains all the data for the tests, in a tuple form ([term1, term2, sum]), then a testcase iterates on the table on invoke the parameterized testcase to test a row in the table :
I would also add negative (overflow here) testing : what is calculate(MAXINT, 1)
supposed to return ?
回答5:
See David Saff's work on Theory Tests; here (PDF) is an example. This is basically a way of making an assertion that something (like a function being the inverse of its function) is true for all values in some set (including the set of all possible values) - and expressing that assertion as a test. You can do some fun stuff by running your test with randomly selected values (if the set is too large to run exhaustively), and automatically recording the failures as specific concrete regression tests.
来源:https://stackoverflow.com/questions/2393024/how-to-test-or-describe-endless-possibilities