您需要扩展 TestRule,尤其是 apply()。例如,查看 org.junit.rules.ExternalResource 和 org.junit.rules.TemporaryFolder。
外部资源如下所示:
public abstract class ExternalResource implements TestRule {
public Statement apply(Statement base, Description description) {
return statement(base);
}
private Statement statement(final Statement base) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
before();
try {
base.evaluate();
} finally {
after();
}
}
};
}
/**
* Override to set up your specific external resource.
* @throws if setup fails (which will disable {@code after}
*/
protected void before() throws Throwable {
// do nothing
}
/**
* Override to tear down your specific external resource.
*/
protected void after() {
// do nothing
}
}
TemporaryFolder 然后扩展它并实现 before() 和 after()。
public class TemporaryFolder extends ExternalResource {
private File folder;
@Override
protected void before() throws Throwable {
// create the folder
}
@Override
protected void after() {
// delete the folder
}
所以 before 在 testMethod 之前被调用,而 after 在 finally 中被调用,但是你可以捕获并记录任何异常,比如:
private Statement statement(final Statement base) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
before();
try {
base.evaluate();
} catch (Exception e) {
log.error("caught Exception", e);
} finally {
after();
}
}
};
}
编辑:以下作品:
public class SoTest {
public class ExceptionLoggingRule implements TestRule {
public Statement apply(Statement base, Description description) {
return statement(base);
}
private Statement statement(final Statement base) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (Exception e) {
System.out.println("caught an exception");
e.printStackTrace(System.out);
throw e;
}
}
};
}
}
@Rule public ExceptionLoggingRule exceptionLoggingRule = new ExceptionLoggingRule();
@Rule public ExpectedException expectedException = ExpectedException.none();
@Test
public void testMe() throws Exception {
expectedException.expect(IOException.class);
throw new IOException("here we are");
}
}
测试通过,您将获得以下输出:
caught an exception
java.io.IOException: here we are
at uk.co.farwell.junit.SoTest.testMe(SoTest.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
...
应用规则的顺序是调用 testMe 方法的 ExceptionLoggingRule 的 ExpectedException。ExceptionLoggingRule 捕获异常,记录并重新抛出它,然后由 ExpectedException 处理。
如果只想记录意外异常,只需切换规则的声明顺序:
@Rule public ExpectedException expectedException = ExpectedException.none();
@Rule public ExceptionLoggingRule exceptionLoggingRule = new ExceptionLoggingRule();
这样,expectedException 被首先应用(即嵌套在 exceptionLoggingRule 中),并且只重新抛出不期望的异常。此外,如果某些异常是预期的并且没有发生,则 expectedException 将抛出一个 AssertionError 也将被记录。
此评估顺序无法保证,但除非您使用非常不同的 JVM,或者在测试类之间继承,否则它不太可能发生变化。
如果评估顺序很重要,那么您始终可以将一条规则传递给另一条规则进行评估。
编辑:使用最近发布的 Junit 4.10,您可以使用 @RuleChain 正确链接规则:
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);
}
}
写日志
starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule