[转]探索JUnit4扩展:深入Rule

系统 2270 0
转载自:
探索JUnit4扩展:深入Rule

本文是"探索JUnit4扩展"系列中的第三篇,将进一步探究Rule的应用,展示如何使用Rule来替代@BeforeClass,@AfterClass,@Before和@After的功能。(2012.01.04最后更新)

在本系列的第二篇 《探索JUnit4扩展:应用Rule》 中提到,可以使用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  evaluate()  throws  Throwable {
            before(base, description);
            
try  {
                base.evaluate();
            } 
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());
        }
    };

    @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 );
    }
}

值得注意的是,classRule是静态变量,它使用@ClassRule Annotation,将替代@BeforeClass和@AfterClass;而rule是成员变量,它使用@Rule Annotation,将替代@Before和@After。与 之前文章 不同的是,此处不仅会在执行测试方法之前打印指定内容的日志(printBeforeLog()),还会在执行测试方法之后打印一条固定格式的日志(printAfterLog()),用于指示该测试方法已经执行完毕了。

3. 小结
    使用Rule可以替代绝大部分的Runner扩展,而且特定的Rule实现可以被复用,也易于添加或移除Rule实例,这些都大大地提高了灵活性。值得注意地是,本文虽然使用Rule代替了@BeforeClass,@AfterClass,@Before和@After的功能,但并不意味着就应当这么做。就我个人所想,将传统的Fixture功能交由@BeforeClass,@AfterClass,@Before和@After实现,仍然是一种不错的选择。

[转]探索JUnit4扩展:深入Rule


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论