本文是"探索JUnit4扩展"系列中的第三篇,将进一步探究Rule的应用,展示如何使用Rule来替代@BeforeClass,@AfterClass,@Before和@After的功能。(2012.01.04最后更新)
在本系列的第二篇http://www.2cto.com/kf/201112/115209.html中提到,可以使用Rule替代现有的大部分Runner扩展,而且也不提倡对Runner中的withBefores(),withAfters()等方法进行扩展。本文将介绍如何使用Rule去实现@Before,@After和@BeforeClass的相同功能。
1. BaseRule
首先要创建一个较通用的TestRule实现BaseRule,它会释放出两个扩展点,一个在执行测试方法之前,before();另一个在执行测试方法之后after()。下面是该类的代码,
public abstract class BaseRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
return new RuleStatement(base, description);
}
private class RuleStatement extends Statement {
private Statement base = null;
private Description description = null;
private RuleStatement(Statement base, Description description) {
this.base = base;
this.description = description;
}
@Override
public void eva luate() throws Throwable {
before(base, description);
try {
base.eva luate();
} finally {
after(base, description);
}
}
}
protected void before(Statement base, Description description) throws Throwable {
}
protected void after(Statement base, Description description) {
}
}如果对JUnit4的源代码略有认知,可能会发现BaseRule与JUnit4提供的TestRule实现ExternalResource代码相似。关键的不同之处是,BaseRule中的before()与after()方法都提供了Statement与Description类型的参数,这使得它能够完成更复杂的工作。
2. CalculatorTest
本文使用的CalculatorTest将不使用@BeforeClass,@Before和@After,而会创建两个BaseRule的实例:一个用于替代@BeforeClass和@AfterClass(本系列目前还未使用过@AfterClass),另一个则替代@Before和@After。
public class CalculatorTest {
private static final DateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss_SSS");
private static Calculator calculator = null;
@ClassRule
public static BaseRule classRule = new BaseRule() {
protected void before(Statement base, Description description) throws Throwable {
calculator = new Calculator();
};
};
@Rule
public BaseRule rule = new BaseRule() {
protected void before(Statement base, Description description) throws Throwable {
printBeforeLog(description);
};
protected void after(Statement base, Description description) {
printAfterLog(description);
};
private void printBeforeLog(Description description) {
TestLogger testLogger = description.getAnnotation(TestLogger.class);
if (testLogger != null) {
StringBuilder log = new StringBuilder(format.format(new Date()));
log.append(" ").append(description.getClassName()).append("#")
.append(description.getMethodName()).append(": ")
.append(testLogger.log());
System.out.println(log.toString());
}
}
private void printAfterLog(Description description) {
StringBuilder log = new StringBuilder(format.format(new Date()));
log.append(" ").append(description.getClassName()).append("#")
.append(description.getMethodName()).append(" end");
System.out.println(log.toString());
}
};
@Te