Rules in JUnit 4.9 (beta 3)

Some time ago David Saff announced a beta release of JUnit 4.9. So I guess it is a good point in time to look into what is new in this version.

One of the most useful innovations in the JUnit realm have been Rules. I wrote about Rules here. And I wrote about use cases for JUnit Rules here. Rules are great. And with JUnit 4.9 they get even better.

You can think of Rules as a way to encapsulate setup and teardown of a test in one class instead of two methods. But Rules are also a way to modify the way to execute your tests. You can run tests a dozen time instead of once. Or in twenty different threads. Interestingly there were only Rules for single tests. So if you want to stick with the comparison with setup and teardown, aka @Before and @After there wasn’t a @BeforeClass and @AfterClass equivalent in Rules.

Now that has changed. You can now annotate a public static field of type TestRule with the @ClassRule and it will behave just like a Rule that is defined for a whole test class instead of a single test. So it is perfect for the stuff that needs setup once for all the tests instead of for each tests. Lets look at an example.

The implementation of a Rule might look like this:

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
 
public class LoggingRule implements TestRule {
 
 public class LoggingStatement extends Statement {
 
  private final Statement statement;
 
  public LoggingStatement(Statement aStatement, String aName) {
   statement = aStatement;
  }
 
  @Override
  public void evaluate() throws Throwable {
   System.out.println("before: " + name);
   statement.evaluate();
   System.out.println("after: " + name);
  }
 
 }
 
 private final String name;
 
 public LoggingRule(String aName) {
  name = aName;
 }
 
 @Override
 public Statement apply(Statement statement, Description description) {
  System.out.println("apply: " + name);
 
  return new LoggingStatement(statement, name);
 }
 
}

Most implementations will consist of two parts: An implementation of the TestRule interface and an implementation of the Statement interface.

TestRule replaces the now deprecated MethodRule interface which was used before. This is because the new interface supports both Rules on class level and on method level, so it had to change a little. TestRule has a single method apply which takes a Statement and returns a Statement. This method gets called before any test in the scope of the Rule gets executed. The Statement passed in actually are the tests that might get executed. Two things to note here: The Statement might and will represent multiple tests, if your Rule gets used with a @ClassRule annotation; And the call to apply doesn’t mean the Statement will actually get executed. Since whatever your Rule returns might get passed to other Rules, the Statements might got mangled in various ways before the contained tests get actually executed. The typical thing todo in the apply method is to wrap the Statement in a new Statement which will perform what ever logic is needed for your purpose.

The Statement interface has a single method evaluate which should execute a test or a bunch of tests in the normal case. So if you go with the typical approach mentioned above you do some setup call evaluate of the contained Statement and do some tear down. In the example provided above I print stuff on the console so one can see in which order stuff gets called. The Statement also gets passed a Description which contains useful meta information about the test(s). It contains the name, the class in which the test is defined, the method name and makes annotations available. So your Rule/Statement can fine tune its behavior based on the test method on which it operates.

A test class using this Rule might look like this:

import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
 
public class RuleTest {
 
 @ClassRule
 public static LoggingRule classRule = new LoggingRule("classrule");
 
 @Rule
 public static LoggingRule rule = new LoggingRule("rule");
 
 @Test
 public void testSomething() {
  System.out.println("In TestSomething");
  assertTrue(true);
 }
 
 @Test
 public void testSomethingElse() {
  System.out.println("In TestSomethingElse");
  assertTrue(true);
 }
}

The only change to JUnit4.8 Rules is the presence of the @ClassRule annotation. Note that the same class is used with @ClassRule and @Rule annotation.
When executed the output of the test class looks like this:

apply: classrule
before: classrule
apply: rule
before: rule
In TestSomething
after: rule
apply: rule
before: rule
In TestSomethingElse
after: rule
after: classrule

As you can see first the class level Rule gets applied and the resulting Statement evaluated. Only as part of the evaluation does the method level Rule applied and the resulting Statement evaluated, once for each test.
One word of caution: Be careful to use the correct modifiers with your Rules. They must be public and class level Rules must be static. Depending on what you do wrong (and in what environment you are working in) the resulting errors might not be exactly helpful. This is considered a bug and fixes are in the making.

Reference: Rules in JUnit 4.9 (beta 3) from our JCG partner Jens Schauder at the Schauderhaft blog.

Related Articles :

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


6 × = fifty four



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close