Ordering your JUnit Rules using a RuleChain

February 21st, 2012 by

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("[BEFORE] 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
test 2 started
test 1 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 Bitbucket repository – download it there or check it out using Mercurial:

hg clone https://bitbucket.org/hascode/junit-rule-chaining-samples

Resources

Article Updates

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

Tags: , , , , , , , ,

5 Responses to “Ordering your JUnit Rules using a RuleChain”

  1. John Says:

    Where did you see that a rule needs a corresponding annotation? Removing @ConsoleOut bares the same result.

  2. micha kops Says:

    geesh thanks for mentioning .. these were fragments of a first approach where I would have read data from the annotation used in the rule implementation. i’ve updated the article! damn nightly builds :)

  3. ryan Says:

    the console output shows inner, middle, outer, but as far as I can tell from the api documentation it should show outer, middle, inner.

  4. Calfilmmaker Says:

    Can you RuleChain with ClassRules?

  5. Micha Kops Says:

    Calfilmmaker: I’ve added an example using ClassRules!

Leave a Reply

Please note, that no personal information like your IP address is stored and you're not required to enter you real name.

Comments must be approved before they are published, so please be patient after having posted a comment - it might take a short while.

Please leave these two fields as-is:
Search
Categories