JUnit Rules

We all know testing is good for our health right? “Testing rocks, debugging sucks”, I think the good guys at google said it.

When in Java when writing unitary tests, we use JUnit most of the time. JUnit is a *wealth* of features which are mostly unexplored and that can truly make test writing easier and more enjoyable.

I’m planning to write a series on the hidden or the lesser known JUnit.

And the first one today is: Rules.

What Rules allow is, in a word, to run code that wraps the test code under execution. In many cases that’s just code that
initializes and destroys some helper objects that you need in the testing code. So why wouldn’t you put that in methods annotated with @Before/@After? The answer is convenience.

An example is worth 1000 words. Let’s see how @Rule TemporaryFolder is used.

What’s nice about the @Rule in the example above is how the TemporaryFolder functionality is encapsulated, brought up and torn down for each test.

Rules classes like the TemporaryFolder that we just saw need to inherit interface TestRule which only contains the method below:

In the above, the base parameter represents the actual test code. Calling base.evaluate() will trigger the test.

However implementing the TestRule directly is awkward. A more useful class is ExternalResource (which TemporaryFolder also inherits and specializes for temporary files). This allows using in the test code a resource which is initialized/destroyed. As example, say we wanted to use in our test an http client.

And to use this rule in an actual test:

There are a bunch of other @Rule that ship with JUnit which be tremendously useful:

  • TemporaryFolder – as described above, makes dealing with temporary files pretty painless
  • ExternalResource – generalizes resource set up and tear down
  • ErrorCollector – allows test to continue even after the first problem occurs; the purpose here is to collect all problems in one go
  • Verifier – do checks *after* the test has run and was successful
  • TestWatcher – offers hooks into tests passing or failing; can, for instance, be used in order to make a log of tests that passed/failed
  • TestName – makes possible to have the current test name accessible inside the test itself
  • TimeoutRule – enforce a timeout for the whole test execution
  • ExpectedException – allows specifying exceptions that are allowed to be thrown from the test body. This can also be implemented using the “expect” parameter of the @Test annotation, but I find the ExpectedException easier to use than writing an annotation array
  • ClassRule – applies the same lifecycle as the standard @Rule, but this time to the whole fixture
  • RuleChain – used to order rules

I hope this was a good introduction to rules and that you will put them to good use in your tests.

Leave a Reply

Your email address will not be published. Required fields are marked *