According to the 4.12 release notes, it is possible to annotate static members of a test class with both @Rule and @ClassRule:
a static member annotated with both @Rule and @ClassRule is now considered valid. This means a single rule may be used to perform actions both before/after a class (e.g. setup/tear down an external resource) and between tests (e.g. reset the external resource),
I want to use this functionality to initialize a resource at the beginning of all tests in the file, do some cleanup on the resource between each test, and dispose of it after all tests have finished. This resource is currently represented by a class that extends ExternalResource.
In my before
and after
methods, how can I differentiate between "before/after all tests" and "before/after each test"? Do I need to use a different/custom implementation of TestRule
to accomplish this?
You can implement TestRule#apply
and use the isTest
and isSuite
methods of Description
to determine what kind of Statement
your TestRule
is being applied to.
Here's an example interface you could build to give a rule that has full before
, after
, verify
, beforeClass
, afterClass
, verifyClass
type behavior:
public interface CombinedRule extends TestRule {
default Statement apply(Statement base, Description description) {
if (description.isTest()) {
return new Statement() {
public void evaluate() throws Throwable {
before();
try {
base.evaluate();
verify();
} finally {
after();
}
}
};
}
if (description.isSuite()) {
return new Statement() {
public void evaluate() throws Throwable {
beforeClass();
try {
base.evaluate();
verifyClass();
} finally {
afterClass();
}
}
};
}
return base;
}
default void before() throws Exception {
//let the implementer decide whether this method is useful to implement
}
default void after() {
//let the implementer decide whether this method is useful to implement
}
/**
* Only runs for Tests that pass
*/
default void verify() {
//let the implementer decide whether this method is useful to implement
}
default void beforeClass() throws Exception {
before();
}
default void afterClass() {
after();
}
/**
* Only runs for Suites that pass
*/
default void verifyClass() {
verify();
}
}
The methods annotated with @Before
and @After
will be run before and after each test, while those annotated with @BeforeClass
and @AfterClass
will be run before and after the first/last test in the class respectively.
The before/after methods of a @Rule
are executed before and after each test, while the before/after methods of a @ClassRule
are run before/after the whole test class.
You can use an ExternalResource for either the @Rule
or @ClassRule
case as long as the handler methods react properly for both scenarios. As far as I can tell from the documentation, there is no means of distinguishing between the two rule categories within the rule class methods. If you use the rule class for both cases, it will be applied the same for both.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With