1. Overview

In this tutorial, we'll look at the built-in JUnit test rules. In the end, we'll have the knowledge to use them at appropriate places.

2. Get Current Test Name

Let's start with the TestName rule.

The TestName rule enables us to get the current test name:

public class TestNameRuleTest {

    @Rule
    public TestName testName = new TestName();

    @Test
    public void shouldGetTestName() {
        assertThat(testName.getMethodName()).isEqualTo("shouldGetTestName");
    }
}

Here we're getting the test method's name, shouldGetTestName.

3. Collect Errors in Unit Test

ErrorCollector lets us collect errors and evaluate at the end of the unit test:

public class ErrorCollectorRuleTest {

    @Rule
    public final ErrorCollector collector = new ErrorCollector();

    @Test
    public void shouldCollectErrors() {
        Service service = new Service();
        if (!service.canRead()) {
            collector.addError(new Throwable("Cannot read!"));
        }

        if (!service.canWrite()) {
            collector.addError(new Throwable("Cannot write!"));
        }
    }

    public static class Service {

        public boolean canRead() {
            return false;
        }

        public boolean canWrite() {
            return false;
        }
    }
}

Notice that, the test isn't failing at the first error, but continuing to execute. In the end, all failures will be printed.

4. Set Timeout in Unit Test

Timeout class lets us set a timeout for all tests in a test class:

public class TimeoutRuleTest {

    @Rule
    public Timeout timeout = new Timeout(1000, TimeUnit.MILLISECONDS);

    @Test
    public void shouldNotTimeout() {
        sleep(500);
    }

    @Test
    public void shouldTimeout() {
        sleep(1500);
    }

    private void sleep(long milliseconds) {
        try {
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) {
            fail();
        }
    }
}

Here, we're defining the timeout to be 1000 milliseconds. If the timeout is reached, it'll throw an exception.

5. Define Expectations on Exceptions

Next, ExpectedException lets us define exceptions that we expect to be thrown:

public class ExpectedExceptionRuleTest {

    @Rule
    public final ExpectedException thrown = ExpectedException.none();

    @Test
    public void shouldThrowException() {
        thrown.expect(NullPointerException.class);
        thrown.expectMessage("Value is null");

        throw new NullPointerException("Value is null");
    }
}

Note that we can define expectations on both the exception type and message.

6. Create Temporary Files and Folders in Unit Test

TemporaryFolder helps us when creating temporary files and folders in our tests:

public class TemporaryFolderRuleTest {

    @Rule
    public TemporaryFolder temporaryFolder = new TemporaryFolder();

    @Test
    public void shouldCreateNewFile() throws IOException {
        File file = temporaryFolder.newFile();

        assertThat(file.isFile()).isTrue();
        assertThat(file.isDirectory()).isFalse();
    }

    @Test
    public void shouldCreateNewFileWithGivenName() throws IOException {
        String fileName = "test.txt";
        File file = temporaryFolder.newFile(fileName);

        assertThat(file.getName()).isEqualTo(fileName);
        assertThat(file.isFile()).isTrue();
        assertThat(file.isDirectory()).isFalse();
    }

    @Test
    public void shouldCreateNewFolder() throws IOException {
        File folder = temporaryFolder.newFolder();

        assertThat(folder.isFile()).isFalse();
        assertThat(folder.isDirectory()).isTrue();
    }

    @Test
    public void shouldCreateNewFolderWithGivenName() throws IOException {
        String folderName = "test";
        File folder = temporaryFolder.newFolder(folderName);

        assertThat(folder.getName()).isEqualTo(folderName);
        assertThat(folder.isFile()).isFalse();
        assertThat(folder.isDirectory()).isTrue();
    }

}

Here, we're creating temporary files and folders. Note that we can specify the file/folder name. Moreover, these files will be removed when the test is completed.

7. Manage External Resources

Lastly, ExternalResource provides a template to set up and clean up resources.

It has two methods we should implement: before() and after():

public class ExternalResourceRuleTest {

    private Server myServer = new Server();

    @Rule
    public final ExternalResource resource = new ExternalResource() {
        @Override
        protected void before() throws Throwable {
            myServer.connect();
        }

        @Override
        protected void after() {
            myServer.disconnect();
        }
    };

    @Test
    public void shouldManageExternalResource() {
        System.out.println("Client can connect now!");
    }

    public static class Server {

        public void connect() {
            System.out.println("Connecting to the server");
        }

        public void disconnect() {
            System.out.println("Disconnecting from the server");
        }
    }
}

We're connecting to a server in the before() method. Then we're disconnecting from the server in after() method.

8. Summary

In this tutorial, we've seen different test rules which JUnit provides by default.

As always, the source code is available on Github.