junit Fixtures


Example

From Wikipedia:

A test fixture is something used to consistently test some item, device, or piece of software.

It can also enhance readability of tests by extracting common initialisation / finalisation code from the test methods themselves.

Where common initialisation can be executed once instead of before each tests, this can also reduce the amount of time taken to run tests.

The example below is contrived to show the main options provided by JUnit. Assume a class Foo which is expensive to initialise:

public class Foo {
    public Foo() {
        // expensive initialization
    }

    public void cleanUp() {
        // cleans up resources
    }
}

Another class Bar has a reference to Foo:

public class Bar {
    private Foo foo;
    
    public Bar(Foo foo) {
        this.foo = foo;
    }

    public void cleanUp() {
        // cleans up resources
    }
}

The tests below expect an initial context of a List containing a single Bar.

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.Arrays;
import java.util.List;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class FixturesTest {
    
    private static Foo referenceFoo;
    
    private List<Bar> testContext;
    
    @BeforeClass
    public static void setupOnce() {
        // Called once before any tests have run
        referenceFoo = new Foo();
    }

    @Before
    public void setup() {
        // Called before each test is run
        testContext = Arrays.asList(new Bar(referenceFoo));
    }
    
    @Test
    public void testSingle() {
        assertEquals("Wrong test context size", 1, testContext.size());
        Bar baz = testContext.get(0);
        assertEquals(referenceFoo, baz.getFoo());
    }
    
    @Test
    public void testMultiple() {
        testContext.add(new Bar(referenceFoo));
        assertEquals("Wrong test context size", 2, testContext.size());
        for (Bar baz : testContext) {
            assertEquals(referenceFoo, baz.getFoo());
        }
    }
    
    @After
    public void tearDown() {
        // Called after each test is run
        for (Bar baz : testContext) {
            baz.cleanUp();
        }
    }
    
    @AfterClass
    public void tearDownOnce() {
        // Called once after all tests have run
        referenceFoo.cleanUp();
    }
}

In the example the @BeforeClass annotated method setupOnce() is used to create the Foo object, which is expensive to initialise. It is important that it not be modified by any of the tests, otherwise the outcome of the test run could be dependent on the order of execution of the individual tests. The idea is that each test is independent and tests one small feature.

The @Before annotated method setup() sets up the test context. The context may be modified during test execution, which is why it must be initialised before each test. The equivalent effect could be achieved by including the code contained in this method at the start of each test method.

The @After annotated method tearDown() cleans up resources within the test context. It is called after each test invocation, and as such is often used to free resources allocated in a @Before annotated method.

The @AfterClass annotated method tearDownOnce() cleans up resources once all tests have run. Such methods are typically used to free resources allocated during initialisation or in a @BeforeClass annotated method. That said, it's probably best to avoid external resources in unit tests so that the tests don't depend on anything outside the test class.