Set Up and Tear Down

Problem

You want to avoid duplicated code when several tests share the same initialization and cleanup code.

Solution

Use the setUp( ) and tearDown( ) methods. Both of these methods are part of the junit.framework.TestCase class.

Discussion

JUnit follows a very specific sequence of events when invoking tests. First, it constructs a new instance of the test case for each test method. Thus, if you have five test methods, JUnit constructs five instances of your test case. For this reason, instance variables cannot be used to share state between test methods. After constructing all of the test case objects, JUnit follows these steps for each test method:

  • Calls the test case’s setUp( ) method

  • Calls the test method

  • Calls the test case’s tearDown( ) method

This process repeats for each of the test methods in the test case. Example 4-3 shows how you can take advantage of setUp( ) and tearDown( ) to avoid duplicated code.

Example 4-3. setUp( ) and tearDown( )

package com.oreilly.javaxp.junit;

import com.oreilly.javaxp.common.BadGameException;
import com.oreilly.javaxp.common.Game;
import com.oreilly.javaxp.common.Ship;
import junit.framework.TestCase;

/**
 * Sample unit tests for the {@link Game} class.
 */
public class TestGame extends TestCase {
    private Game game;
    private Ship fighter;

    public void setUp(  ) throws BadGameException {
        this.game = new Game(  );
        this.fighter = this.game.createFighter("001");
    }

                      public void tearDown(  ) {
        this.game.shutdown(  );
    }

    public void testCreateFighter(  ) {
        assertEquals("Fighter did not have the correct identifier",
                "001", this.fighter.getId(  ));
    }

    public void testSameFighters(  ) {
        Ship fighter2 = this.game.createFighter("001");
        assertSame("createFighter with same id should return same object",
                this.fighter, fighter2);
    }

    public void testGameInitialState(  ) {
        assertTrue("A new game should not be started yet",
                !this.game.isPlaying(  ));
    }
}

You can often ignore the tearDown( ) method because individual unit tests are not long-running processes, and objects are garbage-collected as soon as the JVM exits. tearDown( ) can be useful, however, if your tests do things like open database connections, show GUI frames, or consume other sorts of system resources that you would like to clean up immediately. If you are running a large suite of unit tests, setting references to null in your tearDown( ) methods may help the garbage collector reclaim memory as other tests run.

You may be wondering why you should write a setUp( ) method instead of simply initializing fields in a test case’s constructor. After all, since a new instance of the test case is created for each of its test methods, the constructor is always called before setUp( ). In a vast majority of cases, you can use the constructor instead of setUp( ) without any side effects.

In cases where your test case is part of a deeper inheritance hierarchy, you may wish to postpone object initialization until instances of derived classes are fully constructed. This is a good technical reason why you might want to use setUp( ) instead of a constructor for initialization. Using setUp( ) and tearDown( ) is also good for documentation purposes, simply because it may make the code easier to read.

See Also

Recipe 4.7 shows how to set up data once for a whole series of tests.

Get Java Extreme Programming Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.