Thomas A. Alspaugh
JUnit

About JUnit

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/

Overview and Idiom of Use

  1. Define a class for your tests and give it a method for each group of tests you want to run. Annotate each test method with @org.junit.Test (or simply @Test if you import org.junit.*). JUnit will use the annotations to find all the test methods at run time, using reflection (Class.getMethods(), then Method.getAnnotation()). Within each test method, call assert*() methods to test your test results.
  2. If two or more of your test methods depend on the same test setup code, you can create a test fixture method 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.

  3. Run your tests by calling the org.junit.runner.JUnitCore.runClasses() method with your test classes C1 through Cn as its arguments.

    (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.

Assertion Methods

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.

Assertions about a single value

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)

Assertions about two values

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.

Assertions about two arrays of values

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)

Assertions that use matchers

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.

Assertions that always fail

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");
  }

Testing for Exceptions

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.

Testing from Javadoc

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.

@return (non-void methods only)

Make assertions about the returned value, based on what the @return tag comment claims.

Code for TestReturns.java  (testing java.lang.String#charAt)

package junit_example;
import org.junit.*;


/**
  Class for testing return values.
  The java.lang.CharSequence class method charAt() is tested.
*/
public class TestReturns {

  static private CharSequence abc = "abc";

  @Test
  public void charAt() {
    //  "The first char value is at index 0."
    Assert.assertEquals('a', abc.charAt(0));
    //  "the char value at the specified index of this string."
    Assert.assertEquals('b', abc.charAt(1));
    Assert.assertEquals('c', abc.charAt(2));
  }

}

@throws (non-void methods only)

Test that appropriate exceptions are thrown, based on what the @throws tag comment claims.

Code for TestThrows.java  (testing java.lang.String#charAt)

package junit_example;
import org.junit.*;


/**
  Class for testing thrown exceptions.
  The java.lang.CharSequence class method charAt() is tested.
*/
public class TestThrows {

  static private CharSequence abc = "abc";

  @Test(expected = IndexOutOfBoundsException.class)
  public void charAtNeg1() {
    //  "IndexOutOfBoundsException - if the index argument is negative"
    abc.charAt(-1);
  }

  @Test(expected = IndexOutOfBoundsException.class)
  public void charAtNeg22() {
    //  "IndexOutOfBoundsException - if the index argument is negative"
    abc.charAt(-22);
  }

  @Test(expected = IndexOutOfBoundsException.class)
  public void charAt3() {
    //  "IndexOutOfBoundsException - if the index argument is ...
    //    not less than length()."
    abc.charAt(3);
  }

  @Test(expected = IndexOutOfBoundsException.class)
  public void charAt73() {
    //  "IndexOutOfBoundsException - if the index argument is ...
    //    not less than length()."
    abc.charAt(73);
  }

}

Side effects on the object (mutable objects only)

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.

Code for TestSides.java  (testing java.lang.StringBuilder)

package junit_example;
import org.junit.*;


/**
  Class for testing side effects.
  The java.lang.StringBuilder class is tested.
  This class will test some return values and throws as well.
*/
public class TestSides {

  @Test
  public void testStringBuilder() {
    final StringBuilder buf = new StringBuilder();
    //  "Constructs a string builder with no characters in it"
    Assert.assertEquals(0, buf.length());
    //  "initial capacity of 16 characters"
    Assert.assertEquals(16, buf.capacity());
    //  "Returns: a reference to this object."
    Assert.assertSame(buf, buf.append("de"));
    //  Length is previous length (0) + length of appended string.
    Assert.assertEquals(2, buf.length());
    //  "As long as the length of the character sequence contained
    //    in the string builder does not exceed the capacity,
    //    it is not necessary to allocate a new internal buffer"
    Assert.assertEquals(16, buf.capacity());
    //  "Then the character at index k in the new character sequence
    //    is equal to the character at index k in the old character
    //    sequence, if k is less than n; otherwise, it is equal to
    //    the character at index k-n in the argument str."
    Assert.assertEquals('d', buf.charAt(0));
    Assert.assertEquals('e', buf.charAt(1));
  }

}

Side effects on arguments

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.

References

The latest javadoc for JUnit.

The JUnit Cookbook.

Java Unit testing with JUnit 4.x in Eclipse

flip bgunflip