JUnit uses the java.lang.Class class and reflection to identify your test methods at run time, run them, and produce useful error messages. The goal of doing so is to minimize the code you need to write for useful tests. This page discusses how to use JUnit 4, the release current at this writing. Earlier versions used somewhat different models and scenarios of use, and future versions will no doubt ring in additional changes.
The JUnit packages, javadoc, and other information are available online at http://www.junit.org/
test fixturemethod in your test class that sets up the data needed by tests, and annotate it with @org.junit.Before (@Before). If a test fixture sets up any permanent resources that you want to release after the test is done, write a teardown method in the test class and annotate it with @org.junit.After (@After). JUnit uses the annotations to find and run setup and teardown methods, using reflection.
These annotations are necessary because JUnit will call your test methods in an arbitrary sequence, so each test method has to be independent of all the other ones.
(This may seem odd, as most methods have a fixed number of parameters. Java 5.0 introduced variable arity methods in which the last parameter, if its type T is followed by … , can be instantiated by any number of arguments. In the call, the arguments for that parameter are separated by commas, and in the method, the last parameter is used as if it had been declared T[] rather than T… ).
You pass in a test class using its class literal (which probably seems equally odd to you): the class literal for any class C is written C.class. The .class looks like a static field of your class but is in fact a use of Java's class keyword.
runClasses(C1.class, C2.class, … , Cn.class);
Alternatively, run your test classes from the command line with the command
java org.junit.runner.JUnitCore C1 C2 … Cn
Eclipse has its own facilities for running your JUnit tests.
The class org.junit.Assert is a class with no objects and only static methods, providing a variety of methods for checking results. Each method throws an AssertionError if its arguments don't match up appropriately, and otherwise does nothing. The methods are static and void (returning no value). Some of the methods have a message parameter whose value (if not null) is used in any thrown error. The methods fall into several groups.
assertFalse (Boolean | condition) | ||
assertFalse (String | message, | boolean | condition) |
Each of these throws the error if condition isn't false. The version with String message includes the message in the thrown error.
The remaining methods are just listed, not described, unless what the method does isn't obvious from its name. In addition, nearly all the other methods have a version with the message parameter, and that second method won't be mentioned again.
assertTrue (Boolean | condition) | ||
assertNotNull(Object | reference) | ||
assertNull (Object | reference) |
assertEquals (Object | expected, | Object | actual) |
assertSame (Object | expected, | Object | actual) |
assertNotSame(Object | expected, | Object | actual) |
assertEquals (long | expected, | long | actual) |
assertEquals (double | expected, | double | actual, double delta) |
assertEquals(Object, Object) uses the object's isEqual() method to compare them, while assertSame(Object, Object) and assertNotSame(Object, Object) use ==.
The delta parameter states how close expected and actual must be to be considered equal for the purposes of the assertion.
assertArrayEquals(byte[] | expected, | byte[] | actual) |
assertArrayEquals(char[] | expected, | char[] | actual) |
assertArrayEquals(double[] | expected, | double[] | actual, float delta) |
assertArrayEquals(float[] | expected, | float[] | actual, float delta) |
assertArrayEquals(int[] | expected, | int[] | actual) |
assertArrayEquals(long[] | expected, | long[] | actual) |
assertArrayEquals(Object[] | expected, | Object[] | actual) |
assertArrayEquals(short[] | expected, | short[] | actual) |
assertThat(T actual, Matcher<T> matcher) uses a matcher to decide if actual is what it should be. Matchers are not further discussed here; see the JUnit javadoc for more information.
fail() and its more useful twin fail(String message) are used if the test is more complicated than what the other methods provide. The idiom is
if (!ComplicatedTest) {
fail("DescriptiveMessage");
}
JUnit provides a parameter for the @Test annotation to check that an expected exception is thrown. The exception class is given (using a class literal) as the value for @Test's parameter expected. The following example test succeeds if it throws an IndexOutOfBoundsException and fails otherwise:
// Test that String's charAt method throws IndexOutOfBoundsException // for a negative index: @Test(expected = IndexOutOfBoundsException.class) public void NegativeIndex() { char cc = (new String("abc")).charAt(-1); }
The test fails if it throws no exception, or if it throws a different exception.
A good Javadoc specification of a constructor or method gives you the information you need to test it.
The categories of tests described below are those appropriate for testing any software, and are described here in terms of Javadoc for convenience.
Make assertions about the returned value, based on what the @return tag comment claims.
Test that appropriate exceptions are thrown, based on what the @throws tag comment claims.
Some classes have methods with side effects, or consequences other than returning a value or throwing an exception. The String class does not have such methods (tested above through its CharSequence interface); all its objects are immutable, i.e. they do not change state. The StringBuilder class, on the other hand, does have such methods; a StringBuilder object has a state that can be changed by appending characters, deleting characters, and so forth.
Side effects are tested for by calling the method, then calling other methods that are non-mutating (methods that don't change the object's state) and that return values reflecting the new state, and testing these return values.
Some methods have side effects on objects passed in through parameters. An example is the java.util.Collections method sort(List<T>). This method is static, so it has no this object whose state it could affect, and it is void so there is no return value to test. The effect of this method is seen on its List argument, which after the call is sorted in its natural order (of course, it may already have been sorted before the call). This method would be tested by examining the list argument after the call, using the approach described above in Side effects.
The latest javadoc for JUnit.
The JUnit Cookbook.