JUnit Rules are a handy solution if one needs to alter test methods or wants to share common functionality between several test cases. JUnit 4.10 introduced a new class to order several rules according to our needs using a so called rule-chain.

In the following example, we’re going to create a simple custom rule and afterwards bind several instances of it in a specified order to a test method.

Adding JUnit

Just one Maven dependency needed here – JUnit 4.10

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.10</version>
    <scope>test</scope>
</dependency>

Rule definition

Now we need to define a role – as you might remember a role consists of an annotation (that’s what is used in the test case) and and implementation class that implements TestRule.

We’re going a simple rule that adds some console logging to our test methods – it takes a note as constructor string argument and prints it when the rule is applied later.

package com.hascode.tutorial;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

public class ConsoleOutRule implements TestRule {
    private final String note;

    public ConsoleOutRule(final String note) {
      this.note = note;
    }

    public Statement apply(final Statement base, final Description description) {
        System.out.println("rule applied. note: " + note);
        return base;
    }
}

Applying the Rule to a Test Case

If we wanted to modify a test with our new rule, this could be a scenario

package com.hascode.tutorial;

import static org.junit.Assert.assertTrue;

import org.junit.Rule;
import org.junit.Test;

public class SomeUnitTest {
    @Rule
    public ConsoleOutRule rule = new ConsoleOutRule("somewhere");

    @Test
    public void testSomeMethod() {
      System.out.println("test started");
      assertTrue(true);
    }
}

Running the test would produce the following output:

rule applied. note: somewhere
test started

Ordering Rules with RuleChains

Finally we’re wrapping several rules using RuleChain’s static builder methods

package com.hascode.tutorial;

import static org.junit.Assert.assertTrue;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;

public class SomeUnitTestWithRuleChain {
    @Rule
    public TestRule chain = RuleChain.outerRule(new ConsoleOutRule("outer"))
        .around(new ConsoleOutRule("middle"))
        .around(new ConsoleOutRule("inner"));

    @Test
    public void testSomeMethod() {
        System.out.println("test started");
        assertTrue(true);
    }
}

The following output is produced

rule applied. note: inner
rule applied. note: middle
rule applied. note: outer
test started

Ordering ClassRules with RuleChains

The following example show how to order class rules:

package com.hascode.tutorial;

import static org.junit.Assert.assertTrue;

import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.ExternalResource;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;

public class SomeUnitTestWithRuleChain {

  @ClassRule
  public static TestRule chain = RuleChain.outerRule(new ConsoleOutTestWrapper("outer"))
      .around(new ConsoleOutTestWrapper("middle"))
      .around(new ConsoleOutTestWrapper("inner"));

  @Test
  public void testSomeMethod1() {
    System.out.println("test 1 started");
    assertTrue(true);
  }

  @Test
  public void testSomeMethod2() {
    System.out.println("test 2 started");
    assertTrue(true);
  }

  static class ConsoleOutTestWrapper extends ExternalResource {

    private final String note;

    ConsoleOutTestWrapper(String note) {
      this.note = note;
    }

    @Override
    protected void before() throws Throwable {
      System.out.printf("[BEFORE] rule applied. note: %s%n", note);
    }

    @Override
    protected void after() {
      System.out.printf("[AFTER] rule applied. note: %s%n", note);
    }
  }

}

This produces the following output:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.hascode.tutorial.SomeUnitTestWithRuleChain
[BEFORE] rule applied. note: outer
[BEFORE] rule applied. note: middle
[BEFORE] rule applied. note: inner
test2 started
test1 started
[AFTER] rule applied. note: inner
[AFTER] rule applied. note: middle
[AFTER] rule applied. note: outer
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.029 sec

Tutorial Sources

I have put the source from this tutorial on my GitHub repository – download it there or check it out:

git clone https://github.com/hascode/junit-rule-chaining-samples

Article Updates

  • 2018-11-28: Typo in ConsoleOutTestWrapper fixed (thanks @Serg for mentioning)

  • 2018-06-24: Examples for ordering class rules added.