Unit Test Frameworks
Authors: Hamill P.
Published year: 2006
Pages: 39-42/146
Buy this book on amazon.com >>
     

Chapter 6. JUnit

Section 6.1.   Overview

Section 6.2.   Architecture

Section 6.3.   Usage

Section 6.4.   Test Assert Methods

     

6.1 Overview

The JUnit unit test framework is the reference implementation of xUnit. As its name implies, it is developed in and used with Java. It is undoubtedly the most widely used, extended, and discussed framework for software unit testing today. JUnit is the foundation for more specialized unit testing tools, including Cactus, Jester, JUnitPerf, and many more, and integrates closely with others, such as Ant. The large community of JUnit users means that it is the basis for many new ideas and developments in unit testing technology.

The generic xUnit architecture, described in Chapter 3, reflects the architecture of JUnit. Java is designed from the ground up as a true object-oriented language, incorporating many modern features such as pure abstract classes, object reflection, and native exception-handling. JUnit makes full use of these features.

The purpose of JUnit is to provide a framework for building and running unit tests. The JUnit distribution also is a great example of a simple, solid software product that is built using test driven development. Examining its source code is instructive.

JUnit is open source software released under the Common Public License. This license frees all contributors from any liability or responsibility for the code, and makes users free to distribute, copy, alter, sell, and otherwise have their way with it. For details, refer to http://www.opensource.org.

The definitive source for everything pertaining to JUnit is http://www.junit.org. The information given in this book is based on JUnit 3.8.1, the current version of JUnit as of this writing.

     

6.2 Architecture

JUnit contains about 75 named classes plus a number of inner classes and interfaces. It is organized into packages, as shown in Figure 6-1.

Figure 6-1. The JUnit packages and their import dependencies
figs/utf_0601.gif

The package junit.framework represents the core functionality, and the foundation on which unit tests are built. Much of the rest of the code is the relatively complex Swing, AWT, and text user interface (UI) packages, the package junit.samples (containing unit test examples), and the package junit.tests (containing JUnit's own unit tests). JUnit's developers "eat their own dog food" by providing a complete set of unit tests for all of its functionality.

The class architecture for the package junit.framework is shown in Figure 6-2.

Figure 6-2. Class architecture of the package junit.framework
figs/utf_0602.gif

The architecture of junit.framework follows the generic xUnit architectural model described in Chapter 3. In particular, notice a key architectural element, the interface Test , which is implemented by the classes TestCase and TestSuite . The abstract class TestCase is the parent of all unit test classes.

As described in Chapter 3, the key classes used when building unit tests are TestCase , TestSuite , and the TestRunner s. Appendix B is a detailed class reference for the junit.framework package.

     

6.3 Usage

This section presents a quick overview of basic JUnit usage. The xUnit examples in the previous chapters provide a more detailed review of how to use JUnit.

Test classes in JUnit are subclasses of TestCase . Tests can be built in a number of ways, but the conventional approach is described here. The name of the test class starts with the name of the object being tested and ends with Test . Test classes contain a separate test method for each behavior being tested. Test methods are named starting with test .

Test conditions are checked with test assert methods . Test asserts result in test success or failure. If the assert fails, the test method returns immediately. If it succeeds, the execution of the test method continues. Since a test method should only test a single behavior, in most cases, each test method should only contain one test assert.

If there are objects that are shared by the test methods, they should be initialized in the setUp() method and destroyed in tearDown( ) . These methods are called before and after each test method call, effectively recreating the test fixture for each test, thereby providing test isolation.

Example 6-1 shows a test class built following this model, called LibraryTest , that (naturally) tests the class Library .

Example 6-1. The test class LibraryTest
LibraryTest.java

import junit.framework.*;

import java.util.*;



public class

LibraryTest

extends TestCase {



   private

Library

library;



   public void

setUp

( ) throws Exception {

      library = new Library( );

      library.addBook(new Book( "Cosmos", "Carl Sagan" ));

      library.addBook(new Book( "Contact", "Carl Sagan" ));

      library.addBook(new Book( "Solaris", "Stanislaw Lem" ));

      library.addBook(new Book( "American Beauty", "Allen M Steele" ));

      library.addBook(new Book( "American Beauty", "Edna Ferber" ));

   }



   public void

tearDown

( ) {

      library.empty( );

      library = null;

   }



   public void

testGetBooksByTitle

( ) {

      Vector books = library.getBooksByTitle( "American Beauty" );

assertEquals

( "wrong number of books found", 2, books.size( ) );

   }



   public void

testGetBooksByAuthor

( ) {

      Vector books = library.getBooksByAuthor( "Carl Sagan" );

assertEquals

( "2 books not found", 2, books.size( ) );

   }



   public void

testEmpty

( ) {

      library.empty( );

assertEquals

( "library not empty", 0, library.getNumBooks( ) );

   }

}

LibraryTest is a test fixture because there are multiple test methods sharing an objectin this case, an instance of Library . The Library is created and loaded with a set of Book s in setUp( ) and emptied and disposed of in tearDown( ) .

Each test method verifies a distinct behavior of the Library class with a single test assert. Although the tests may modify the Library , as shown by testEmpty( ) , the test fixture functionality guarantees that each test runs in a clean fixture, without dependencies on the results of the others.

Tests are run using one of the TestRunner tools provided with JUnit. The simplest and most easily automated of these is TextTestRunner . Example 6-2 demonstrates using TextTestRunner to run LibraryTest .

Example 6-2. Running LibraryTest with the TextTestRunner
$ java junit.textui.TestRunner LibraryTest

.........

Time: 0.01



OK (3 tests)

It often is useful to aggregate multiple tests so they can be run together. The class TestSuite is used to contain a collection of tests. Example 6-3 shows a class, LibraryTests , which creates a TestSuite containing a number of test classes. The static method suite( ) creates and returns the TestSuite .

Example 6-3. The class LibraryTests
LibraryTests.java

import junit.framework.*;



public class

LibraryTests

extends TestSuite {



   public static Test

suite

( ) {

      TestSuite suite = new TestSuite( );

      suite.addTest(new TestSuite(

BookTest

.class));

      suite.addTest(new TestSuite(

LibraryTest

.class));

      suite.addTest(new TestSuite(

LibraryDBTest

.class));

      suite.addTest(new TestSuite(

LibraryPerfTest

.class));

      return suite;

   }

}

When LibraryTests is run using TextTestRunner , all of the test methods in each test class are found and run, as shown in Example 6-4.

Example 6-4. Running the LibraryTests test suite
$ java junit.textui.TestRunner LibraryTests

.................

Time: 0.851



OK (17 tests)

The GUI TestRunner can be used instead of TextTestRunner . The Swing version of TestRunner is invoked for LibraryTest as shown:

$ java junit.swingui.TestRunner LibraryTest

Figure 6-3 shows the result after the TestRunner GUI runs LibraryTest .

Figure 6-3. The Swing TestRunner after LibraryTest is run
figs/utf_0603.gif

Unit Test Frameworks
Authors: Hamill P.
Published year: 2006
Pages: 39-42/146
Buy this book on amazon.com >>

Similar books on Amazon