Sometime ago I blogged about JUnit @Rule Annotation. In the meantime I got the chance to use rules in a real project. I must say: Rules rock! Let me tell you about my use cases.
- I am working on a Swing project (It's OK, it's not as bad as it sounds). We have many tests that create components and check certain properties. Although they never get shown in the traditional sense, Swing documentation requires all manipulation of Swing Components to happen in the Event Dispatch Thread. We have an EDTRule, which runs every test using SwingUtilities.invokeAndWait(). It works like a charm. We actually had a dozen tests that would fail under real weird conditions, which behave nicely since they where adorned with an EDTRule. While the Rule takes care on the threading requirements, test stay nicely clean and don't get poluted by SwingUtilities and Runnable implementations.
- Another class of tests runs scripts against a database. In order to reproduce what the database admins will do, we use SQL/Plus for this (If you don't know SQL/Plus consider yourself lucky). One problem with these test is, that a small bug in a script might cause SQL/Plus to await user input. In order to prevent the test to hang forever we implemented a TimeoutRule. Each script that gets started puts its Process instance into the rule instance, and the rule instance will destroy the Process after some specified time. Note: JUnit comes with a similar Timeout rule, which will let the test fail after a timeout.
- We have an ApplicationRegistry, which is basically a singleton map containing Implementations for Interfaces. Each test should setup the ApplicationRegistry with whatever is needed, and clean it up afterwards. Often developers forget the last part (When I say developers I am talking about myself). For this we have an ApplicationRegistryRule. It cleans the ApplicationRegistry before the test and after the test. Since it is only one Rule instead of a Before and an After method, it is easier not to forget one half of it. But the Rule does more: Before cleaning it, it checks if the ApplicationRegistry is empty. If it isn't this means, some other test left it dirty. In this case the Rule calls Assertion.fail(). This way we found (probably) every test which left the ApplicationRegistry dirty. Very cool. A similar approach should work for other central resources like Spring Contexts and the like.