Taking your example (with a bit of refactoring),
assert(a + b, math.add(a, b));
doesn't help to:
- understand how
math.add
behaves internally,
- know what will happen with edge cases.
It's pretty much as saying:
- If you want to know what the method does, go and see the hundreds of lines of source code yourself (because, yes,
math.add
can contain hundreds of LOC; see below).
- I don't bother to know if the method works correctly. It's ok if both expected and actual values are different from what I really expected.
This also means that you don't have to add tests like:
assert(3, math.add(1, 2));
assert(4, math.add(2, 2));
They don't help neither, or at least, once you made the first assertion, the second one brings nothing useful.
Instead, what about:
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.");
This is self-explanatory and damn helpful both for you and for the person who will maintain the source code later. Imagine that this person does a slight modification to the math.add
to simplify the code and optimize the performance, and sees the test result like:
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
this person will understand immediately that the newly modified method depends on the order of the arguments: if the first argument is an integer and the second one is a long numeric, the result would be an integer, while a long numeric was expected.
In the same way, obtaining the actual value of 4.141592
at the first assertion is self-explanatory: you know that the method is expected to deal with a big precision, but actually, it fails.
For the very same reason, two following assertions can make sense in some languages:
// 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));
Also, what about:
assert(numeric.Infinity, math.add(numeric.Infinity, 1));
Self-explanatory too: you want your method to be able to deal correctly with the infinity. Going beyond infinity or throwing an exception is not an expected behavior.
Or maybe, depending on your language, this will make more sense?
/**
* 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?
No one really knows :)