From version 4.7, JUnit introduced a new concept called Rules which really helpful. Rules allow very flexible addition or redefinition of the behavior of each test method in a test class. Testers can reuse or extend one of the provided Rules below, or write their own. Here are some of the rules:
- TemporaryFolder Rule allows creation of files and folders that are guaranteed to be deleted when the test method finishes (whether it passes or fails).
public static class HasTempFolder {
@Rule
public TemporaryFolder folder= new TemporaryFolder();
@Test
public void testUsingTempFolder() throws IOException {
File createdFile= folder.newFile(“myfile.txt”);
File createdFolder= folder.newFolder(“subfolder”);
// …
}
}
- ExternalResource is a base class for Rules (like TemporaryFolder) that set up an external resource before a test (a file, socket, server, database connection, etc.), and guarantee to tear it down afterward.
public static class UsesExternalResource {
Server myServer = new Server();
@Rule
public ExternalResource resource = new ExternalResource() {
@Override
protected void before() throws Throwable {
myServer.connect();
};
@Override
protected void after() {
myServer.disconnect();
};
};
@Test public void testFoo() {
new Client().run(myServer);
}
}
- ErrorCollector Rule allows execution of a test to continue after the first problem is found (for example, to collect _all_ the incorrect rows in a table, and report them all at once).
- Timeout Rule applies the same timeout to all test methods in a class
- ExpectedException Rule allows in-test specification of expected exception types and messages.
In version 4.9, JUnit introduced Test-class and suite level Rules. The `ClassRule` annotation extends the idea of method-level Rules, adding static fields that can affect the operation of a whole class. Any subclass of `ParentRunner`, including the standard `BlockJUnit4ClassRunner` and `Suite` classes, will support `ClassRule`s.
In version 4.10, JUnit introduced RuleChain which allows ordering of TestRules.
public static class UseRuleChain {
@Rule
public TestRule chain= RuleChain
.outerRule(new LoggingRule(“outer rule”)
.around(new LoggingRule(“middle rule”)
.around(new LoggingRule(“inner rule”);
@Test
public void example() {
assertTrue(true);
}
}
As it said, testers can reuse or extend existing rule, also can write their own rules. One library System Rules implemented by Marc Philipp and Stefan Birkner is sometimes very useful. The System Rules is a collection of JUnit rules for testing code which uses java.lang.System Class. It can help for testing with System.getProperty, System.setProperty, System.exit, System.getSecurityManager, System.err, System.in, System.out.
For example: in some case, we may let system exit using System.exit(0). But this is regarded by JUnit as an error: junit.framework.AssertionFailedError: Forked Java VM exited abnormally. With System Rules, you can
@Rule
public final ExpectedSystemExit exit = ExpectedSystemExit.none();
@Test
public void systemExit(){
exit.expectSystemExitWithStatus(-1);
//… the code will call System.exit()
}
References:
- https://raw.github.com/KentBeck/junit/23ffc6baf5768057e366e183e53f4dfa86fbb005/doc/ReleaseNotes4.7.txt
- http://stefanbirkner.github.com/system-rules/