JUnit Theories and Other Beasts, Part 1
1 June 2012, by Rowan Hill
In this series of four posts, we’ll take a look at how you can make the most out of JUnit, including some of its slightly less well known features. These posts don’t explicitly assume the reader has a firm grasp of JUnit, but an at least passing familiarity with the basics of unit testing will be beneficial. Having said that, the technical material starts quite slowly, so if you’re interested, feel free to follow along, and read around the links provided as we go.
Bread and butter
If you’ve worked on a Java project, you’ve probably spent some time working with the very popular JUnit testing framework. Even if you haven’t, you’ve probably worked with something xUnit compatible (like NUnit, Test::Unit, PyUnit, JsUnit, OCUnit, PHPUnit, etc etc) so the rest of this series of posts may still be of interest – although it is fairly Java-centric there are parallels in NUnit, at least. If you’re still at a loss, quickly go and read the summary in the JUnit Cookbook.
If, like me, you’d assumed JUnit’s capabilities were fairly prosaic, perhaps you’re missing a trick. Until recently, I wasn’t really aware that JUnit provided anything beyond the basic annotations and methods:
- @Before / @After for per-test setup and tear-down
- @BeforeClass / @AfterClass for per-class setup and tear-down
- @Test for specifying a test method (and any expected exceptions)
- assertTrue, assertEqual, and all the Assert.* friends for actually testing the results of your object under test
For the most part, that’s probably enough to get you by, but if you’re willing to dig around a little (JUnit don’t seem to be great at publicising their own capabilities), there are some interesting other things out there.
In this series of posts, we’ll take a look at some of the things you can do with JUnit that go beyond the basics. In later posts, we’ll take an especially close look at JUnit’s theories, but let’s not get ahead of ourselves…
Running away with it
Have you ever wondered what it is that actually takes all of your unit tests and puts them through their paces? Something has to know what a @Test method looks like, for instance, or that @Before methods need running first, what to do when an assertion fails, or when a test passes, or the many other things that need to be done to make your tests come to life.
In JUnit, this is called a Runner. You can specify how you want your test classes to be run by specifying a Runner subclass in the @RunWith annotation on your test class. Whilst you can write your own, you’re much more likely to use one of the Runners that come with JUnit, e.g.:
- Suite, which you can use to run your test suite class, specifying the test classes to run with SuiteClasses. If you have anything more than a modestly sized suite, you may want to use a slightly customised variant of this (such as the fully featured CPSuite) to dynamically create your suite and save yourself a lot of typing (not to mention having to keep remembering to add test classes to your suite).
- Categories, a subclass of Suite that allows you to include/exlcude tests on the specified classes which have the specified @Category. For example, the docs suggest slow tests and fast tests, but you could use it to isolate tests for a particular feature across multiple components, or anything else you can dream up.
- Parameterized, which will run all the tests in your class with the values in each Object element of a specially defined List as the test class’s constructor parameters (although you’ll typically only have one test per class when using Parameterized). This lets you test lots and lots of values easily – and add new ones when you come across a bug. Personally, I find this implementation is actually quite inflexible and ugly, mostly due to the fact that input data is defined per-class, rather than per-method, and the need for a constructor. TestNG, an alternative to JUnit, seems to have a much more pleasant approach that ties data to tests, but I haven’t actually used it myself.
Ruling the roost
Although you can write your own Runner subclass, there hasn’t historically been too much call for it, and there’s even less so with the introduction of the @Rule annotation. Note that although @Rule and friends were introduced in JUnit 4.7, there were substantial changes in 4.9 (outlined in the release notes) and some additions in 4.10, so it’s worth making sure you’re up to date before you dive in.
The @Rule (or @ClassRule) annotation can be applied to a field of type TestRule. The JUnit Runner will call the apply() method of all of the rules it can find in turn, allowing each to inspect, modify, or replace the passed Statement. The Statement object represents the current progress of the test’s execution, which makes rules a powerful tool for extending JUnit and bending it to your will.
If the order of your rules is sensitive, you can define it by using a RuleChain – this itself implements TestRule, so is likely to be the only annotated rule in your class, but will reference all your other rules to specify their execution order.
As with runners, JUnit comes with a few out-of-the-box helpful implementations, e.g.:
- ExternalResource, for setting up and tearing down external resources for your tests, like a server they need to access.
- TestWatcher, to notify you when various events occur in the execution of your tests (such as test start, or failure).
- ExpectedException, for more flexible, in-test specification of expected exceptions.
- And all the others in the org.junit.rules package.
Of course, you’re welcome to invent your own rules, too, to suit your situation. For example, I’ve used rules with WebDriver to make a continuous integration server functional test build take screenshots on failure (but before any tear-down actions) and save them to disk, to help debug intermittently failing tests.
Tune in next time
That’s all for now, but look out for the next post in this series, where we’ll start to take a look at JUnit theories…