Javanook Home

Roll Your Own Unit Tests with JUnit

Tools >> Open Source | JUnit


Unit test, as the name implies, is written to test a single unit of functionality in an application. By “unit of functionality” we mean a single facet of an application functionality that comprises a set of closely related methods and classes. 

Unit testing is not acceptance testing. Unlike acceptance testing which is meant to test application functionality at a high level, unit tests are intended to be fine-grained, that is, they are designed to test individual classes and methods in an application. If your unit tests are becoming too complex with too many dependencies, consider refactoring your code to break it into smaller modules. If you don’t, you will end up writing acceptance tests instead of unit tests.

Unit tests are written prior to writing code for the functionality. This seems contrary to the conventional wisdom that testing is at the end of code implementation. A typical unit test cycle runs as follows:
- Write a unit test for the new feature you want to add to the application.
- Run the test. You will notice that it fails, of course, since you have not yet written the code for the new feature.
- Add the implementation code for the new feature.
- Run the test again. You will notice that it passes if the implementation is right.
- If the test fails, correct the code and re-run the test.
- Repeat the last step until the test passes.

Who writes my unit tests? 
The programmer, of course, writes the unit tests. You test your code as you write it, since you understand your code better than anyone else, and as it happens so often, you can anticipate the problems you are likely to encounter later. If you can think of ways to break the code, translate them into unit tests. Does it mean the programmer’s effort is doubled, since almost every method or class that is likely to break the functionality needs a unit test? Probably yes, but the effort pays off in the long run. This is known as test-driven development, and is at the heart of Extreme Programming (XP).

Unit tests are written primarily to test new features and to test for bugs in an application. You write a unit test prior to adding the new feature, but write a unit test after a bug is reported. In both cases, the unit test cycle remains the same as outlined before. 

In addition, you write unit tests for any method that has a non-trivial implementation. A hard to understand code is prime candidate for a unit test. Trivial methods do sometimes grow in complexity as the application develops with more features. In that case, the programmer’s better judgment shall prevail so that a unit test is attached to it right at the beginning.

Writing Unit Tests in Java
JUnit is the unit test framework in Java. It enables automated unit testing which is central to XP. The JUnit API is extensible and toolable. It is integrated into many Java IDEs, including the open source Eclipse. It is also available as an executable task in the build tool Ant.

JUnit, an open source Java tool, is available from http://www.junit.org. It has become the de facto standard for creating automated unit tests in Java. JUnit makes it easy to launch unit testing from within an application. Automation in unit testing implies running without human intervention.

Unit testing in Java using JUnit begins with the creation of test cases. A JUnit test case is a Java class that has one or more unit test methods. Test cases may be grouped into what is called a test suite. You can run the tests independently, or execute the entire test suite at once.

Every JUnit test case is a subclass of junit.framework.TestCase. The unit test is actually a method within the TestCase subclass. It is of the form testXXX(). Each test case contains one or more unit tests.

JUnit prescribes certain conventions to enable it to locate and run the test methods automatically. Each unit test shall be a public method without arguments. The method name shall begin with the keyword test. There is a workaround for it, but it is best to follow this convention. JUnit locates unit tests by means of Java’s reflection mechanism.

JUnit tests are simple pass/fail tests that use one or more boolean tests of the form assertXXX(). Several overloaded assertXXX() methods are available to test different program conditions. Some of them are

Although it is possible to get by with these two methods in most cases, the JUnit framework has many more to perform various other tests such as checking for a null condition.

Let us look at an example to trace a unit test from creation to execution.

Listing 1
public class SimpleMath {

public SimpleMath() {
}

public int add(int x, int y) {
return x+y;
}

public int sub(int x, int y) {
return x-y;
}

public int div(int x, int y) {
if(y == 0) {
return -1;
}
return (int)(x/y);
}

public int mul(int x, int y) {
return x*y;
}
}

Let us now write a simple test case for the simple math class above.

Listing 2
import junit.framework.TestCase;

public class TestSimpleMath extends TestCase {

SimpleMath math;

/**
* Constructor not required for versions above V3.7
* @param methodName the name of the test method
* JUnit locates and executes test methods automatically
*/
public TestSimpleMath(String methodName) {
super(methodName);
math = new SimpleMath();
}

/**
* A unit test to verify div() method handles divide by zero correctly
*/
public void testDiv() {
assertEquals(-1, math.div(3,0));
}
}

Running JUnit
Download your copy of junit.jar and include it in the classpath. JUnit can run tests in text or graphical mode. To run the test in a graphical mode, use

junit.swingui.TestRunner

The text mode runs faster, and is suitable for automated testing. It is invoked from the command line as shown below.

java junit.textui.TestRunner TestSimpleMath

The output on the command console is
.
Time: 0

OK (1 tests)

Each test is represented by a dot (.) on the first line of output. The test passes when an assertXXX() method passes. To show a test failure, the letter F follows the dot in the output. 

You may experiment with other values and other test cases until you are comfortable using the JUnit framework.

What are the benefits of Unit Testing?
When you write unit tests you will sometimes feel that you must use more than one assertXXX() statements in a single test. When this happens, if one test failure occurs, the remainder assertXXX() statements will not be executed. This means one of two things – either your test design is wrong, or your code does too many things and needs refactoring. Refactoring improves design, and good unit testing will not leave anything uncovered. 

When you have a situation where you need to check for multiple conditions in a test. When the first condition fails, the subsequent tests will always fail. In that case, having multiple asssertXXX() statements in a single test case, of course, becomes necessary. The programmer writes the unit tests, and, as a programmer, you are the best judge of your code.

Automated unit testing is central to XP, and in all probability programmers will create and run the tests frequently during the continuous integration build process.

As JUnit is now available with most IDEs, and also with build tools like Ant, it becomes much easier to create and run the unit tests.