The first time I stumbled over a JUnit @Rule annotation I was a bit irritated of the concept. Having a public field in a test case seemed somewhat odd and so I was reluctant to use it regularly. But after a while I got used to that and it turned out that rules can ease writing tests in many ways. This post gives a quick introduction of the concept and some short examples of what rules are good for.

What are JUnit Rules?

Let’s start with a look at a JUnit out-of-the-box rule. The TemporaryFolder is a test helper that can be used to create files and folders located under the file system directory for temporary content . The interesting thing with the TemporaryFolder is that it guarantees to delete its files and folders when the test method finishes . To work as expected the temporary folder instance must be assigned to an @Rule annotated field that must be public, not static, and a subtype of TestRule :

public class MyTest { @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @Test public void testRun() throws IOException { assertTrue( temporaryFolder.newFolder().exists() ); } }

How does it work?

Rules provide a possibility to intercept test method calls similar as an AOP framework would do. Comparable to an around advice in AspectJ you can do useful things before and/or after the actual test execution . Although this sounds complicated it is quite easy to achieve.

Testing with JUnit Testing with JUnit is one of the most valuable skills a Java developer can learn. No matter what your specific background, whether you’re simply interested in building up a safety net to reduce regressions of your desktop application or in improving your server-side reliability based on robust and reusable components, unit testing is the way to go. Frank has written a book that gives a profound entry point in the essentials of testing with JUnit and prepares you for test-related daily work challenges. Get It Now!

The API part of a rule definition has to implement TestRule. The only method of this interface called apply returns a Statement . Statement s represent – simply spoken – your tests within the JUnit runtime and Statement#evaluate() executes them. Now the basic idea is to provide wrapper extensions of Statement that can do the actual contributions by overriding Statement#evaluate() :

public class MyRule implements TestRule { @Override public Statement apply( Statement base, Description description ) { return new MyStatement( base ); } } public class MyStatement extends Statement { private final Statement base; public MyStatement( Statement base ) { this.base = base; } @Override public void evaluate() throws Throwable { System.out.println( "before" ); try { base.evaluate(); } finally { System.out.println( "after" ); } } }

MyStatement is implemented as wrapper that is used in MyRule#apply(Statement,Destination) to wrap the original statement given as argument. It is easy to see that the wrapper overrides Statement#evaluate() to do something before and after the actual evaluation of the test .

The next snippet shows how MyRule can be used exactly the same way as the TemporaryFolder above:

public class MyTest { @Rule public MyRule myRule = new MyRule(); @Test public void testRun() { System.out.println( "during" ); } }

Launching the test case leads to the following console output which proves that our example rule works as expected. The test execution gets intercepted and modified by our rule to print ‘before’ and ‘after’ around the ‘during’ of the test:

before during after

Now that the basics are understood let’s have a look at slightly more useful things you could do with rules.

Test Fixtures

Quoted from the according wikipedia section a test fixture ‘is all the things that must be in place in order to run a test and expect a particular outcome. Frequently fixtures are created by handling setUp() and tearDown() events of the unit testing framework’.

With JUnit this often looks somewhat like this:

public class MyTest { private MyFixture myFixture; @Test public void testRun1() { myFixture.configure1(); // do some testing here } @Test public void testRun2() { myFixture.configure2(); // do some testing here } @Before public void setUp() { myFixture = new MyFixture(); } @After public void tearDown() { myFixture.dispose(); } }

Consider you use a particular fixture the way shown above in many of your tests. In that case it could be nice to get rid of the setUp() and tearDown() methods. Given the sections above we now know that this can be done by changing MyFixture to implement TestRule . An appropriate Statement implementation would have to ensure that it calls MyFixture#dispose() and could look like this:

public class MyFixtureStatement extends Statement { private final Statement base; private final MyFixture fixture; public MyFixtureStatement( Statement base, MyFixture fixture ) { this.base = base; this.fixture = fixture; } @Override public void evaluate() throws Throwable { try { base.evaluate(); } finally { fixture.dispose(); } } }

With this in place the test above can be rewritten as:

public class MyTest { @Rule public MyFixture myFixture = new MyFixture(); @Test public void testRun1() { myFixture.configure1(); // do some testing here } @Test public void testRun2() { myFixture.configure2(); // do some testing here } }

I come to appreciate the more compact form of writing tests using rules in a lot of cases, but surely this is also a question of taste and what you consider better to read .

Fixture Configuration with Method Annotations

So far I have silently ignored the Description argument of TestRule#apply(Statement,Description) . In general a Description describes a test which is about to run or has been run. But it also allows access to some reflective information about the underlying java method. Among others it is possible to read the annotations attached to such a method. This enables us to combine rules with method annotations for convenience configuration of a TestRule .

Consider this annotation type:

@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Configuration { String value(); }

Combined with the following snippet inside MyFixture#apply(Statement,Destination) that reads the configuration value annotated to a certain test method…

Configuration annotation = description.getAnnotation( Configuration.class ); String value = annotation.value(); // do something useful with value

… the test case above that demonstrates the usage of the MyFixture rule can be rewritten to:

public class MyTest { @Rule public MyFixture myFixture = new MyFixture(); @Test @Configuration( value = "configuration1" ) public void testRun1() { // do some testing here } @Test @Configuration( value = "configuration2" ) public void testRun2() { // do some testing here } }

Of course there are limitations to the latter approach due to the fact that annotations only allow Enum s, Class es or String literals as parameters. But there are use cases where this is completely sufficient. A nice example using rules combined with method annotations is provided by the restfuse library. If you are interested in a real world example you should have a look at the library’s implementation of the Destination rule .

Comming to the end the only thing left to say is that I would love to hear from you about other useful examples of JUnit rules you might use to ease your daily testing work :-)

It would be remiss not to tell you that chapter 6, It would be remiss not to tell you that chapter 6, Reducing Boilerplate with JUnit Rules , of my book Testing with JUnit is available as a free reading sample at https://www.packtpub.com/packtlib/book/Application%20Development/9781782166603/6 . So, in case you're not tired of my scribblings yet, boldly go ahead and take the opportunity to delve deeper into the world of JUnit rules...

Update 2014/09/01: Rule Ordering:

Sometimes you use more than one rule in a test case. If for some reason you have to define an order of how these rules are nested at runtime, JUnit offers the type RuleChain. This class provides the methods outerRule and around to configure an execution chain of TestRule s in a fluent interface like style. Please have a look at the API for more information.

Update 2014/09/01: Rule Resources:

1) JUnit provides a set of rule implementations that are described in the Rules section of the tool’s online documentation.

2) Thanks to Benny for hinting me at the System Rules library, which provides a collection of rules for testing code that uses java.lang.System .

3) Last but not least we have described a couple of custom rules on our blog.

Update 2014/09/23: JUnit in a Nutshell:

I integrated this post as the fifth chapter into my multi-part tutorial about JUnit testing essentials. So if you are interested in further reading on that topic, here is the chapter navigation:

Title Image: © Depositphotos.com/alexmillos