CIT 590 Unit Testing in Java
Spring 2013, David Matuszek

Why JUnit?

JUnit is the original testing framework, since copied by every other major programming language.

In a sense, the purpose of JUnit testing is to reduce the number of bugs in the final code. Even more importantly, however, extensive use of JUnit, particularly in combination with Test Driven Development, results in substantially better code quality.

JUnit versions

There are two versions of JUnit currently available: JUnit 3 and JUnit 4. Python's unittest is slightly out of date, as it is based on JUnit 3. The most important difference is that JUnit 4 uses annotations (words beginning with @). You should use JUnit 4 for your assignments.

JUnit 3 JUnit 4
import junit.framework.TestCase;

import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

Your class must extend TestCase. Your class can extend any other class you like (Object is the default).
You can override the method
protected void setUp() throws Exception
and it will be executed before every test.
You can annotate a method with @Before, like this:
@Before
public void setUp() throws Exception

and it will be executed before every test. The method can have any name (but it's commonly still named setUp).

You can create as many test methods as you like, but:

  • The method name must begin with test,
  • The method must take no parameters, and
  • The method must return void.

You can create as many test methods as you like, but:

  • The method must be annotated with @Test ,
  • The method must take no parameters, and
  • The method must return void.
You can test whether a method call throws an exception when it is supposed to, but it's complicated. You can specify that a test method should get an exception with the annotation
@Test(expected = ArithmeticException.class)
(or whatever kind of Exception you are expecting).
If a method goes into an infinite loop, the test framework can't get past it. You can set a limit on how many milliseconds a test method is allowed to take with the annotation
@Test(timeout = 1000)
Occasionally you need to do something after each test method. You can do this by overriding the method
protected void tearDown() throws Exception
To execute a JUnit method after each test method, annotate it with
@After.

There about 40 tests that you can use in your test methods; see http://junit.sourceforge.net/javadoc_40/index.html. Here are the ones that I have found to be the most useful.

assertEquals(expected, actual)
Asserts that the actual value equals the expected value. Both expected and actual must be the same type (for example, you cannot test an int against a double). If the two parameters are objects of a class that you have created, the test will use your public boolean equals(Object o) method (or == if you haven't defined equals, which is almost certainly not what you want!).
assertArrayEquals(expectedArray, actualArray)
Like assertEquals, but for arrays. If the elements of the arrays are objects of a class that you have created, the test will use the equals method for that class.
assertEquals(expected, actual, delta)
Asserts that two doubles or floats are equal to within a positive delta.
assertTrue(booleanCondition)
Asserts that the booleanCondition evaluates to true.
assertFalse(booleanCondition)
Asserts that the booleanCondition evaluates to false.
assertNull(object)
Asserts that the object is null.
assertNotNull(object)
Asserts that the object isn't null.
assertSame(expected, actual)
Asserts that the actual argument is another reference to the expected object.
assertNotSame(unexpected, actual)
Asserts that the actual argument is not another reference to the unexpected object.
fail(message)
Causes the test to fail.

Very brief example

Fraction.java FractionTest.java
package fraction;

public class Fraction {
    // Declare instance variables here
    private int numerator;
    private int denominator;

    public Fraction(int numerator, int denominator) {
	    this.numerator = numerator;
		this.denominator = denominator;
    }

    public Fraction add(Fraction f) {
        return null;   // stub
    }
}
The add method above is a stub--it's enough to start creating
the test, but it's certainly returning the wrong answer. The method
should compute and return a Fraction.
package fraction;

import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

public class FractionTest {
    // Declare instance variables here
    Fraction half, quarter;
	
    @Before
    public void setUp() throws Exception {
        // Initialize instance variables here
        half = new Fraction(1, 2);
        quarter = new Fraction(1, 4);
    }

    @Test
    public void testAdd() {
        assertEquals(half, quarter.add(quarter));
     }
}