JUnit is a Java framework for performing unit tests on code. By testing code after every change, programmers can be reassured that changing a small amount of code does not break the larger system. Without automated testing tools like JUnit, retesting can be a tedious and inaccurate process. By allowing the testing process to occur frequently and automatically, you can keep software coding errors at a minimum.
Creating the test cases, however, can be a difficult process requiring knowledge of exactly what the code does and how it should perform. You must carefully create the unit tests performed by JUnit to ensure that the tests rigorously check the code just as it would run in the real world. In this article, we first look at how to create unit tests and then at how to put together test suites.
Creating test cases
Test cases for JUnit are written as Java classes that extend the JUnit framework. These classes have a number of methods, each of which tests a particular function, or unit, of the code. For example, for a simple accounting product, one test might cover logging in with a username and password. A second might check depositing an amount of money and ensure the balance increased by the same amount. A third test might mimic withdrawing money from an account. Generally, the more test cases you write, the more thorough the test will be overall. You should test every functional area of a product: Only by doing this will the tests be of real value in making sure that small changes in one place do not have larger implications in another.
Creating a new test case is easy. As you see in Listing A, writing a new test case requires creating a new Java class. This class must extend the TestCase class and have a constructor that calls the constructor of the base class.
This class is called the test harness, and it’s where you write your tests. Each time a test is called, JUnit will execute the setUp() method for you to initialize any values you need. Next, it will call a test case and then call tearDown() to undo the initialization and go on to the next test.
This simple test harness contains two tests, testBooleanTrue() and testBooleanFalse(). Each test must be declared public and must make a call to JUnit to inform JUnit of the status of the test. In this case, we force one test to always succeed and the other to always fail.
Now, let’s look at a real test case for more detail. For our example, we’ll test the Xerces XML parser, which is freely available from the Apache XML project. We will test against a simple XML document, shown in Listing B.
Our test harness is shown in Listing C.
The test harness for XMLTest.java contains two tests. The first, testPersonCount(), checks to see if there are between zero and 10 person elements listed in the XML document. If there are, then the test case returns true to the assertTrue() method, and the test is a success. However, if there are too few or too many entries, then the test case fails. The other test ensures that the person “James Scheinblum” is contained in the file. We can try either test by editing the Example.xml document.
This test makes good use of the setUp() and tearDown() methods by making sure that for each test, the XML document is reloaded. If any of the exceptions are thrown, such as for a malformed XML document or inability to open the document for reading, the test calls the fail method, which tells JUnit that a failure has occurred, just as when a false result is passed to assertTrue(). The different assertions are documented in the JavaDocs for JUnit, available here.
Now that we’ve created our tests, we want to run them. To do so, however, we need to first create a test suite.
Creating test suites
A test suite is a collection of tests that should be performed in the same session. Suites are a way of grouping tests together for execution, whether or not the tests are in the same file. Listing D shows what our suite looks like for the two tests in Listing C. We’ll use this method definition in the next section when we execute the tests.
Which tests to run?
In our test suite, we’ve explicitly defined which tests to run. That means as we write more tests, we’ll need to add them to the test suite. By explicitly defining the tests to run, we also define the order in which they run.
Alternately, you can automatically discover the test cases by using reflection. This means you write the test suite once, and on each execution, it dynamically determines which tests are available and runs them. The downside is you can’t exclude tests to run, and you can’t control the order in which the tests are executed. However, reflection does ensure that you don’t skip a step in creating the test cases by not adding the test to the suite.
Listing E shows how to pass the class name to the suite constructor to automatically load the tests.
Now let’s take our suite and execute the tests.
Running JUnit tests
To execute the tests, we need to create an executable class that calls the JUnit test runner. The runner will execute the suite, run all the tests, and output the results. Listing F shows how to integrate the test suite into the test runner.
As you can see, the test runner doesn’t care if the suite explicitly defines the tests to run or if it uses reflection to determine the test names.
When everything goes right, JUnit will execute output like that in Listing G.
However, when something goes wrong, you’ll get output like that in Listing H.
Creating test cases in JUnit is simple and can help minimize errors in the software development process. For more information, visit JUnit.org.