Methods & Tools Software Development Magazine

Software Development Magazine - Programming, Software Testing, Project Management, Jobs

JUnit

Axel Irriger, cirquent GmbH, http://www.cirquent.de

JUnit is a Java library for testing source code, which has advanced to the de-facto standard in unit testing. By using JUnit, you can assert that methods in your Java code work as designed, without the need to set up the complete application. From JUnit 4.0 on, the minimum supported Java version is 1.5.0. JUnit version 3.8 and earlier supports Java up to version 1.4. To apply the JUnit principle for testing in specific domains such as XML or databases, special extensions exist.

Web Site: http://www.junit.org and http://junit.sourceforge.net (http://www.sourceforge.net/projects/junit/ respectively)
Version Tested: JUnit 3.8.2 and JUnit 4.8.1 on Windows XP with Java 1.6.0_20
License & Pricing: Open Source
Support: User mailing list (http://tech.groups.yahoo.com/group/junit/), various forums and printed books

Since annotations add a fundamental new programming feature to the Java programming language, JUnit explicitly supports those with version 4.0 and above only, so both major versions (with and without annotation support) will be covered in separate sections.

Installation

The JUnit distribution is downloaded as a single JAR file, which can be placed in any folder. To actually start using JUnit, the JAR must only be put in the classpath of the application to test.

If you are using Apache Ant (http://ant.apache.org) as the build tool in your environment, just include junit.jar to your CLASSPATH. Then, you can use the <junit/> Ant task to actually execute tests. In your build.xml file you can add the following to one of your targets to enable JUnit testing:

<junit>
  <test name="my.test.TestCase"/>
</junit>

This will execute the class my.test.TestCase as a JUnit test. The JUnit Ant task does support both JUnit 3.x and JUnit 4.x versions.

If you are using Apache Maven (http://maven.apache.org) as the build tool in your environment, just add the following to your pom.xml:

<dependencies>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>3.8.2</version>
		<scope>test</scope>
	</dependency>
</dependencies>

This will add JUnit to the build lifecycle. If you already have a "dependencies" element, just add the single "dependency" element to your POM. The unit testing will start by executing the following command:

mvn test

By changing the version above in pom.xml, you can easily switch to different JUnit versions. Maven supports both JUnit 3.x and 4.x.

JUnit 3

JUnit version 3.x is the tool of choice if you need to test your application in a Java 1.4 environment or earlier context. To understand the basic mechanism of JUnit, take a look at Figure 1.

Figure 1 Design of JUnit 3.x

The basic principle of JUnit is the Test interface. Everything is a test and thus, tests can be grouped together. This concept and its implication will be discussed later on. If you want to actually test a piece of code, you create a class, extending TestCase and add various test methods to it. Consider the following, simple Java class:

public class DummyPojo {
	public int addValues(final int firstInt, final int secondInt) {
		return firstInt + secondInt;
	}
}

To test this class, you can create a TestCase like this:

public class DummyPojoTest extends TestCase { /* (1) */
	DummyPojo pojo;
	
	public void setUp() { /* (2) */
		pojo = new DummyPojo();
	}
	
	public void testAdd() { /* (3) */
		int result = pojo.addValues(5, -5); /* (4) */
		assertEquals(0, result); /* (5) */
		assertNotEquals("Result is 10!?", 10, result); /* (6) */
	}
}

In (1) you create a class which extends the base TestCase class. Then, in (2), a generic setUp method is called. This one is provided by TestCase and is invoked per test method to be executed. The method is meant to initialize everything which is needed for the test methods invoked later. This may be instance variables, authentication and such things.

The same applies for the method tearDown, which is not shown here. This method is called after a test method was executed to clean up the test environment, such as removing data from a database. In line (3) a test method is declared. Each test which should be executed automatically must begin with "test". Line (4) then executes a method under test. The lines (5) and (6) then assert expected values. That is, if the value 0 does not equal result, the test is broken and JUnit will stop proceeding. Line (6) adds readability by providing a message which is shown if the assertion breaks.

By using such an approach, you can not only test the "good cases" of an application, but also the "bad cases" and invariants, as well. This way, the contract of a class can be asserted fairly easily, that is the complete behavior of what to expect from its behavior.

If you have many tests for various classes, testing everything and executing all tests can be cumbersome. Therefore, JUnit offers a principle to logically group tests and thus simplify its execution. To logically group TestCases together, you create a TestSuite. And since a TestSuite also implements the Test interface, various suites can also be grouped together. Using this strategy, a logical hierarchy of tests can be created.

Such a TestSuite can then be executed like any other test in JUnit. If a TestSuite is executed by JUnit, all tests configured for this TestSuite will be executed. By applying this mechanism, you can easily test a whole subsystem by only starting one test, which is very convenient:

public class AllTests extends TestSuite
{
	public static Test suite()
	{
		TestSuite mySuite = new TestSuite( "My subsystem test" );
		mySuite.addTestSuite( mypackage.DummyPojoTest.class );
		// ... add more tests here
		return mySuite;
	}
}

Extending JUnit 3

If you want to provide additional functionality, you can easily extend the framework by extending the TestCase class. Using this method, you can add additional methods for asserting things or simplify 3rd party framework integration.

JUnit 4

If you are already familiar with JUnit 3.x, the transition to JUnit 4 is rather simple. The following transition table helps to migrate from JUnit 3.x to JUnit 4.x:

JUnit 3.x

JUnit 4.x

Base-Class TestCase

(no longer necessary)

Method "setUp"

Annotation @Before

Method "tearDown"

Annotation @After

Test-Method "testXYZ"

Annotation @Test

(no equivalent existing)

Annotation @BeforeClass (Once-and-only setUp)

(no equivalent existing)

Annotation @AfterClass (Once-and-only tearDown)

try { fail() } catch (Exception e) { assertTrue(true) }

Annotation @Test(expected == Exception.class)

Custom implementation for testing long-running operations and timeouts

Annotation @Test(timeout = 1000)

Timeout setting in milliseconds.

Custom implementation to ignore test using TestSuite

Annotation @Ignore

To understand its usage, here is a simple example:

public final class MyTest {
	private DummyPojo pojo;
	@BeforeClass public void initialize() {
		System.out.println("This is printed only once");
	}
	@AfterClass public void destroy() {
		System.out.println("The last thing printed");
	}
	@Before public void setUpMyTest() {
		pojo = new DummyPojo();
	}
	@Test public void adder() {
		final int result = pojo.addValues(5, -5);
		assertEquals(0, result);
	}
	@Ignore @Test public void multiplier() {
		// This test seems broken
		final int result = pojo.addValues(-5, -5);
		assertEquals(25, result);
	}
}

Documentation and Literature

The general documentation of JUnit is available from the projects homepage. A more tutorial-like approach can be found at http://java.sun.com/developer/Books/javaprogramming/ant/ant_chap04.pdf.

If you prefer printed documentation, the commercially available book "Pragmatic Unit Testing In Java With JUnit" (http://www.pragprog.com/titles/utj/pragmatic-unit-testing-in-java-with-junit) is a good choice. As a desk reference, consider the "JUnit Pocket Guide" (http://oreilly.com/catalog/9780596007430).

Summary

JUnit is the de-facto toolkit for testing Java applications and, due to its simplicity, should be the first-choice when testing your applications. Besides the power which can be leveraged out-of-the-box, added value is provided when integrated with third-party extensions, such as:

  • dbUnit, which can test database operations like CREATE, INSERT or database triggers
  • xmlUnit, which simplifies testing XML based applications, such as comparing XML documents, evaluating XPaths, et cetera.

To me, JUnit is in invaluable tool which every Java developer should know about and use heavily in his or her daily work.


More Java Unit Testing Content


Click here to view the complete list of tools reviews

This article was originally published in the Fall 2010 issue of Methods & Tools