Choosing a testing framework is just the first part of the story. The second and most important one is to actually fully and properly test your code. The typical code unit that you'll test is a method. The first thing that you'll have to test is that your method works properly. For example, let's consider the following method: double divide(double number, double divider) throws DivisionByZeroException. Your test would look like this:
public void testMethod() {
double precision = .001;
try {
double result = divide(6, 3);
if (2 - precision < result < 2 + precision)
SUCCESS();
else
FAIL();
} catch (DivisionByZeroException e) {
FAIL();
}
}
This will tell you if your method works properly or not: first, you make sure that no exception is thrown when your method is given a valid set of parameters. You also make sure that the result returned by the method is within specified precision requirements. This is usually called "testing for success".
But what about that exception that is being thrown? It's there to enable programmers to gracefully recover from abnormal execution conditions, such as when the divider is zero. This is a very important aspect because software may cause serious damage if abnormal execution conditions are not properly reported and handled. So just testing that your testing method works properly is not enought. You should also make sure that DivisionByZeroException is thrown when the method is invoked with a divider parameter equal to zero. This is usually called "failure test" and a typical failure test may look like this:
public void testMethod() {
try {
divide(6, 0);
FAIL(); // because the exception should have been thrown
} catch (DivisionByZeroException e) {
SUCCESS(); // because the exception was thrown as excepted, showing that the abnormal condition (an invalid
set of parameters) has been properly detected and reported.
}
}
Testing More Complex Code
The previous example was a very simple one, because the code unit that was tested is very simple. If your algorithm is more complex - that is, if its execution graph is complex - then only one success test may not be enough. To make sure your code is properly tested, you can adopt the following strategy:
identify all the if / else and switch / case constructs - this is called building your algorithm's decision graph. A path through this graph is triggered by a set of input parameters and / or a particular state of the execution environment.
build a set of parameters and an execution environment state for each possible path in the decision graph