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.