Chapter 7. Testing using JUnit

Table of Contents

Writing Unit Tests with JUnit
Simple Test Example
Viewing Test Failures

While compilers can look for structural problems in a program, they cannot tell whether the results of a program or method are correct. Instead, all developers test their programs to ensure that they behave as expected. This can be as simple as calling a method in the Interactions Pane to view its results, but this technique requires you to think about the answers you expect every time you run any tests. A much better solution is to give the tests the answers you expect, and let the tests themselves do all the work.

Thankfully, a technique known as unit testing makes this quite easy. You write many small tests that create your objects and assert that they behave the way you expect in different situations. A unit test framework known as JUnit (http://www.junit.org) automates the process of running these tests, letting you quickly see whether your program returns the results you expect.

DrJava makes the process of running unit tests very simple by providing support for JUnit. Once you have written a JUnit test class (as described in the next section), you can simply choose the "Test Current Document" command from the Tools menu to run the tests and view the results. The name of the tests being run will be shown in the Test Output tab, with each test method turning green if it completes successfully and red if it fails. Any failures will be displayed after the list of methods in the same way as the compiler errors. A progress bar will keep you updated on how many tests have been run.

Also, clicking the "Test" button on the toolbar or choosing "Test All Documents" from the Tools menu will run JUnit on any open testcases, making running multiple test files very simple.

Writing Unit Tests with JUnit

With the JUnit framework, unit tests are any public classes that extend the junit.framework.TestCase class, and that have any number of methods with names beginning with the word "test". JUnit provides methods to easily assert things about your own classes, as well as the ability to run a group of tests.

The requirements for writing unit test classes are described below, with an example provided in the next section. In general, though, the intent is for you to create instances of your classes in the test methods, get results from any methods that you call, and assert that those results match your expectations. If these assertions pass, then your program has behaved correctly and your tests have succeeded.

Writing a Test Case. To use DrJava's Test command on a document, you must use the programming conventions outlined below. You can also choose the "New JUnit Test Case" command from the File menu to automatically generate a template with these conventions.

  • At the top of the file, include:

    import junit.framework.TestCase;
  • The main class of the file must:

    • be public

    • extend TestCase

  • Methods of this class to be run automatically when the Test command is invoked must:

    • be public and not static

    • return void

    • take no arguments

    • have a name beginning with "test"

  • Test methods in this class can call any of the following methods (among others):

    • void assertTrue(String, boolean)

      which issues an error report with the given string if the boolean is false.

    • void assertEquals(String, int, int)

      which issues an error report with the given string if the two integers are not equal. The first int is the expected value, and the second int is the actual (tested) value. Note that this method can also be called using any primitives or with Objects, using their equals() methods for comparison.

    • void fail(String)

      which immediately causes the test to fail, issuing an error report with the given string.

    Test methods are permitted to throw any type of exception, as long as it is declared in the "throws" clause of the method contract. If an exception is thrown, the test fails immediately.

  • If there is any common setup work to be done before running each test (such as initializing instance variables), do it in the body of a method with the following contract:

    protected void setUp()

    This method is automatically run before any tests in the class. (Similarly, you can write a protected void tearDown() method to be called after each test.)

  • If you would rather control which methods are called when running the tests (rather than using all methods starting with "test"), you can write a method to create a test suite. This method should be of the form:

    public static Test suite() {
      TestSuite suite = new TestSuite();
      suite.addTest(new <classname>("<methodname>"));
      ...
      return suite;
    }
    

    It is then also necessary to import TestSuite and Test from junit.framework. There is also a version of the addTest method that takes a Test, so test suites can be composed.

A simple example of a TestCase class is given in the next section. There are many other ways to use JUnit, as well. See the JUnit Cookbook at http://junit.sourceforge.net/doc/cookbook/cookbook.htm for more examples and information.