探索JUnit4扩展:应用Rule(原)

探索JUnit4扩展:应用Rule(原)
探索JUnit4扩展:使用Rule
在上一篇文章 《探索JUnit4扩展:扩展Runner》中,讨论了一种扩展JUnit4的方式,即,直接修改Test Runner的实现(BlockJUnit4ClassRunner)。但这种方法显然不便于灵活地添加或删除扩展功能。本文将使用JUnit4.7才开始引入的扩展方式--Rule来实现相同的扩展功能。(2010.12.25最后更新)

1. Rule
Rule是JUnit4.7才开始提供的一种扩展方式,它能够替代大部分已有的Runner扩展。JUnit包含两种Rule Annotation:@ClassRule与@Rule。@ClassRule应用于测试类中的静态变量,而@Rule应用于成员变量;相同地是,这些变量必须是TestRule接口的实例,且访问修饰符必须为public。
在 上篇博文中,对BlockJUnit4ClassRunner进行了扩展,被扩展的方法是methodBlock,现在我们来看看该方法体中的代码,
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(),withPotentialTimeout(),withBefores()和withAfters()都已经被标注为过时,JUnit建议使用Rule来替代这些方法的功能。

2. TestLogRule
如第1节所述,Rule Annotation要作用于TestRule接口的实例,那么就要先创建一个TestRule的实现类。
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;
    }
}
如上所示,TestLogRule与 上篇博文中的LoggedRunner的代码有许多相同之处,功能则都是打印出指定的日志,每行日志又以当时的执行时间与完整方法名作为前缀。

3. 使用Rule的CalculatorTest
下面是新的测试类CalculatorTest,它将不使用BlockJUnit4ClassRunner的扩展LoggedRunner作为测试执行器,所以该类没有使用@RunWith(LoggedRunner.class),那么在执行该测试类时仍然会使用BlockJUnit4ClassRunner。
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 );
    }
}
与 上篇博文中的CalculatorTest相比,本文中的CalculatorTest除了没有使用LoggedRunner之外,还多了两行代码
@Rule
public  TestLogRule testLogRule  =   new  TestLogRule();
在执行单元测试方法之前,BlockJUnit4ClassRunner会调用TestRule/TestLogRule中的apply()方法,即,会先打印出日志内容。

4. 小结
使用Rule对JUnit进行扩展,能够避免对默认Runner的扩展,为测试类添加或移除Rule十分方便,而且Rule实现类本身也能很方便地被复用。在 下一篇博文中将进一步探索Rule的应用。

你可能感兴趣的:(探索JUnit4扩展:应用Rule(原))