探烦(ch)JUnit4扩展Q用Rule
在上一文?a href="http://www.aygfsteel.com/jiangshachina/archive/2011/12/14/366289.html">《探索JUnit4扩展Q扩展Runner?/a>中,讨论?jin)一U扩展JUnit4的方式,卻I直接修改Test Runner的实?BlockJUnit4ClassRunner)。但q种Ҏ(gu)昄不便于灵zdd或删除扩展功能。本文将使用JUnit4.7才开始引入的扩展方式--Rule来实现相同的扩展功能?2010.12.25最后更?
1. Rule
Rule是JUnit4.7才开始提供的一U扩展方式,它能够替代大部分已有的Runner扩展。JUnit包含两种Rule AnnotationQ@ClassRule与@Rule。@ClassRule应用于测试类中的?rn)态变量,而@Rule应用于成员变量;相同地是Q这些变量必LTestRule接口的实例,且访问修饰符必须为public?br />?a href="http://www.aygfsteel.com/jiangshachina/archive/2011/12/14/366289.html">上篇博文中,对BlockJUnit4ClassRunnerq行?jin)扩展,被扩展的?gu)是methodBlockQ现在我们来看看该方法体中的代码Q?br />protected Statement methodBlock(FrameworkMethod method) {
Object test;
try {
test= new ReflectiveCallable() {
@Override
protected Object runReflectiveCall() throws Throwable {
return createTest();
}
}.run();
} catch (Throwable e) {
return new Fail(e);
}
Statement statement= methodInvoker(method, test);
statement= possiblyExpectingExceptions(method, test, statement);
statement= withPotentialTimeout(method, test, statement);
statement= withBefores(method, test, statement);
statement= withAfters(method, test, statement);
statement= withRules(method, test, statement);
return statement;
}
但在BlockJUnit4ClassRunner中,possiblyExpectingExceptions()QwithPotentialTimeout()QwithBefores()和withAfters()都已l被标注ӞJUnit使用Rule来替代这些方法的功能?br />
2. TestLogRule
如第1节所qͼRule Annotation要作用于TestRule接口的实例,那么p先创Z个TestRule的实现类?br />public class TestLogRule implements TestRule {
private static final DateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss_SSS");
@Override
public Statement apply(Statement base, 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());
}
return base;
}
}
如上所C,TestLogRule?a href="http://www.aygfsteel.com/jiangshachina/archive/2011/12/14/366289.html">上篇博文中的LoggedRunner的代码有许多相同之处Q功能则都是打印出指定的日志Q每行日志又以当时的执行旉与完整方法名作ؓ(f)前缀?br />
3. 使用Rule的CalculatorTest
下面是新的测试类CalculatorTestQ它?yu)不使用BlockJUnit4ClassRunner的扩展LoggedRunner作ؓ(f)试执行器,所以该cL有用@RunWith(LoggedRunner.class)Q那么在执行该测试类时仍然会(x)使用BlockJUnit4ClassRunner?br />public class CalculatorTest {
private static Calculator calculator = null;
@Rule
public TestLogRule testLogRule = new TestLogRule();
@BeforeClass
public static void createCalculator() {
calculator = new Calculator();
}
@Test
@TestLogger(log = "a simple division")
public void simpleDivide() {
int value = calculator.divide(8, 2);
Assert.assertTrue(value == 4);
}
@Test(expected = ArithmeticException.class)
@TestLogger(log = "divided by zero, and an ArithmeticException thrown.")
public void dividedByZero() {
calculator.divide(8, 0);
}
}
?a href="http://www.aygfsteel.com/jiangshachina/archive/2011/12/14/366289.html">上篇博文中的CalculatorTest相比Q本文中的CalculatorTest除了(jin)没有使用LoggedRunner之外Q还多了(jin)两行代码
@Rule
public TestLogRule testLogRule = new TestLogRule();
在执行单元测试方法之前,BlockJUnit4ClassRunner?x)调用TestRule/TestLogRule中的apply()Ҏ(gu)Q即Q会(x)先打印出日志内容?br />
4. 结
使用Rule对JUnitq行扩展Q能够避免对默认Runner的扩展,为测试类d或移除Rule十分方便Q而且Rule实现cLw也能很方便地被复用。在下一博?/a>中将q一步探索Rule的应用?/div>
]]>