Java Programming Tutorials

Java programming tutorials with many code examples!

JUnit Rules – code around tests

JUnit Rules is a flexible mechanism to enhance tests by executing code around them. JUnit provides built-in rules and makes it very easy to write custom rules!

Ever needed to create a temporary directory for tests that would be automatically deleted after each test? Or print test names to see their execution order? JUnit Rules are exactly for that purpose! They execute a piece of code (marked with @Rule annotation) around a test as in the following steps:

  1. JUnit executes a Rule passing to it a data about the current test.
  2. Rule executes part of own code, if any.
  3. Rule then evaluates the test.
  4. Rule executes rest of own code.
  5. JUnit moves to the next test, so and starts from point 1.

JUnit provides a number of built-in rules (you can find them in org.junit.rules package):

  • DisableOnDebug: allows to disable a rule when debugging (it’s often desirable to disable Timeout rule ;-) )
  • ErrorCollector: allows to execute whole test to collect all errors
  • ExpectedException: verifies that code throws expected exception
  • RuleChain: allows to set rules execution order
  • TemporaryFolder: allows to create temporary files and/or directories that will be automagically deleted after each test (successful or not)
  • TestName: provides current test name
  • Timeout: sets timeout on all test methods.

There are also two rules that need to be extended to be used:

  • Stopwatch: measures time spent in tests (since JUnit 4.12),
  • TestWatcher: records test actions (successes and failures)

There is also @ClassRule that works very similarly, but wraps around whole test class instead of single methods.

Let’s look at an example how to instantiate and execute JUnit Rules.

JUnit Rules Example

In the following code we are using TestName rule to have test name available in each test and just print it:

package com.farenda.junit;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

public class RuleTheWorldTest {

    @Rule
    public TestName testName = new TestName();

    @Test
    public void shouldMultiplyNumbers() {
        System.out.println("Executing: " + testName.getMethodName());
        assertThat(7 * 7, is(49));
    }

    @Test
    public void shouldAddNumbers() {
        System.out.println("Executing: " + testName.getMethodName());
        assertThat(7 + 7, is(14));
    }
}

In the next post we’re going to show how to write custom rules to add own enhancements!

How pros do it

The following CompoundoComparatorTests from Spring Framework shows ExpectedException rule in action:

package org.springframework.util.comparator;

import java.util.Comparator;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

/**
 * Test for {@link ComparableComparator}.
 *
 * @author Keith Donald
 * @author Chris Beams
 * @author Phillip Webb
 */
public class CompoundComparatorTests {

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

        @Test
        public void shouldNeedAtLeastOneComparator() {
                Comparator<String> c = new CompoundComparator<String>();
                thrown.expect(IllegalStateException.class);
                c.compare("foo", "bar");
        }

}

Another test PathResourceTests.java, also from Spring Framework, shows two rules in the same test – ExpectedException and TemporaryFolder:

package org.springframework.core.io;

import org.hamcrest.Matchers;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;

import org.springframework.util.FileCopyUtils;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;

/**
 * Unit tests for the {@link PathResource} class.
 *
 * @author Philippe Marschall
 * @author Phillip Webb
 * @author Nicholas Williams
 * @author Stephane Nicoll
 * @author Juergen Hoeller
 */
public class PathResourceTests {

        private static final String NON_EXISTING_FILE =
                        platformPath("src/test/resources/org/springframework/core/io/doesnotexist.properties");


        private static String platformPath(String string) {
                return string.replace('/', File.separatorChar);
        }

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

        @Rule
        public TemporaryFolder temporaryFolder = new TemporaryFolder();

        @Test
        public void nullPath() throws Exception {
                thrown.expect(IllegalArgumentException.class);
                thrown.expectMessage("Path must not be null");
                new PathResource((Path) null);
        }

        @Test
        public void getInputStreamDoesNotExist() throws Exception {
                PathResource resource = new PathResource(NON_EXISTING_FILE);
                thrown.expect(FileNotFoundException.class);
                resource.getInputStream();
        }

        @Test
        public void outputStream() throws Exception {
                PathResource resource = new PathResource(temporaryFolder.newFile("test").toPath());
                FileCopyUtils.copy("test".getBytes(), resource.getOutputStream());
                assertThat(resource.contentLength(), equalTo(4L));
        }

        @Test
        public void doesNotExistOutputStream() throws Exception {
                File file = temporaryFolder.newFile("test");
                file.delete();
                PathResource resource = new PathResource(file.toPath());
                FileCopyUtils.copy("test".getBytes(), resource.getOutputStream());
                assertThat(resource.contentLength(), equalTo(4L));
        }

// other tests cut for brevity

}
Share with the World!