More about JUnit
Improving the output
Test cases should be short and focused on testing a single fact about the class under test. It is important to document each test case with a brief statement stating what is being tested. You can see an example of this in the inline comments inBasketballExample.
When using JUnit, it is easy to make such comments part of the output produced when a test fails.
In each one of the assertEquals methods we can optionally provide a string
message. If the test fails, this string will be printed along with the expected and actual values.
Here is an example.
@Test
public void testInitialDiameter()
{
String msg = "A newly constructed basketball should have the diameter it was constructed with";
Basketball b = new Basketball(5);
assertEquals(msg, 5.0, b.getDiameter(), EPSILON);
}
Now, when the test fails, the output from the failure trace includes the message
explaining what was being tested.
A newly constructed basketball should have the diameter it was constructed with expected:<5.0> but was:<0.0>
Other assertion methods
The most useful methods are the various forms ofassertEquals. (The third and fourth forms are
the ones used for comparing floating-point numbers.)
assertEquals(expectedValue, actualValue)assertEquals(message, expectedValue, actualValue)assertEquals(expectedValue, actualValue, epsilon)assertEquals(message, expectedValue, actualValue, epsilon)
Sometimes you just want to assert that some boolean expression is true or not:
assertTrue(expression)assertTrue(message, expression)assertFalse(expression)assertFalse(message, expression)
And sometimes you want to simply indicate that a test should simply fail if a certain point in the code is reached.
fail()fail(message)
There are a few more that you will probably use only rarely, and you can find the details in the
JUnit API documentation. (Look for the class org.junit.Assert.)
Before and After
You might notice in theBasketballTests class that we had to create a
new Basketball at the beginning of each test case. Almost all test cases
require some sort of initialization, usually the creation of one or more objects.
If the setup is the same for many of test cases,
you can use the @Before annotation to designate a method that the framework
should run before each test case. For the BasketballTests example, we could do
something like this. The setup method will automatically run before
the execution of each test case to initialize the bb variable. This can save
you from writing a lot of repetitive code.
package lab3;
import org.junit.Test;
import org.junit.Before;
import static org.junit.Assert.assertEquals;
public class BasketballTests2
{
// margin of error for floating-point comparisons
private static final double EPSILON = 10e-07;
private Basketball bb;
@Before
public void setup() // runs before every test case
{
bb = new Basketball(5);
}
@Test
public void testInitial()
{
assertEquals(false, bb.isDribbleable());
}
@Test
public void testInitialDiameter()
{
assertEquals(5.0, bb.getDiameter(), EPSILON);
}
@Test
public void testInflate()
{
bb.inflate();
assertEquals(true, bb.isDribbleable());
}
@Test
public void testDiameterAfterInflation()
{
bb.inflate();
assertEquals(5.0, bb.getDiameter(), EPSILON);
}
}
Note that you'll need to add an import statement for org.junit.Before.
Not surprisingly there is also an annotation @After that designates a method to run
after each test case, but it is not nearly as useful as @Before.