Test Classes and the JUnit Test Execution Environment

JUnit sets up the execution environment for tests at the test class file level. I hereby define a Test Class to be any class that contains test methods (test methods were defined in the previous chapter). Test Classes in version JUnit version 4 are a great improvement over version 3.x test classes, which had to subclass a JUnit-provided class. This makes the framework much less invasive and lets you leverage inheritance and other object-oriented features if and where that makes sense.

Example 5.1. Example JUnit test class

import java.sql.Connection;
public class HackerTest extends AbstractClientTest {
    private Connection mkConnection() {  // A utility method
        ...

    @org.junit.Test
    void testPasswordGuessing() {
        Connection conn1 = mkConnection();
        ...
        assertEquals(...
    }

    @org.junit.Test(expected=InterruptedException)
    void testTimeout() {
        ...

    @org.junit.After
    protected void deallocateCacheSpace() {
        ....

    @org.junit.After
    protected void deallocateNameTokens() {
        ...

Your test class may extend some other class. As explained earlier, you may name your test methods anything you wish to. Our sample test class contains a normal instance method named mkConnection. This method must be careful not to depend on the state of instance variables between test runs, the same as the test methods themselves. The test methods must be independent of one another. With JUnit version 4, it isn't even possible to specify the sequence in which your test methods will be executed.

Instance objects which are set up for each test method execution (by @Before methods, and perhaps cleaned up with @After methods) are called Fixtures.

The class contains two test methods, testPasswordGuessing and testTimeout. It also contains two JUnit lifecycle methods, deallocateCacheSpace and deallocateNameTokens. The @Before and @After notations specify methods which will be executed before and after each of your test methods. So, in this case, the method execution sequence would be

except that the sequence of the first three and last three could be exchanged (since JUnit doesn't guarantee the sequence in which test methods are selected), and the sequence of deallocateCacheSpace and deallocateNameTokens could be exchanged (since JUnit doesn't guarantee the sequence of multiple methods which have the same lifecycle attribute).

JUnit catches all AssertionErrors thrown from test methods, and that is what makes test "failures". If any fixture or test method throws anything else, JUnit will catch it, and that is what makes test "errors". Errors indicate that there is something wrong with your test setup or environment, not with the intended subject of the unit test.

The use of attributes is a great improvement over JUnit verision 3.x, where the single allowed setup and single allowed cleanup methods were pre-defined.

There are also @BeforeClass and @AfterClass lifecycle attributes. @BeforeClass doesn't do anything that you couldn't do just as well in the class constructor. but @AfterClass methods can be useful for performing final cleanup after all test methods (and @Afters) in a single test class have completed.


$Revision: 2422 $