探索JUnit4扩展:深入Rule

编程技术  /  houtizong 发布于 3年前   66

        本文将进一步探究Rule的应用,展示如何使用Rule来替代@BeforeClass,@AfterClass,@Before和@After的功能。

        在上一篇中提到,可以使用Rule替代现有的大部分Runner扩展,而且也不提倡对Runner中的withBefores(),withAfters()等方法进行扩展。本文将介绍如何使用Rule去实现@Before,@After和@BeforeClass的相同功能。

1. BaseRule

        首先要创建一个较通用的TestRule实现BaseRule,它会释放出两个扩展点,一个在执行测试方法之前,before();另一个在执行测试方法之后after()。下面是该类的代码:

package com.bijian.study;import org.junit.rules.TestRule;import org.junit.runner.Description;import org.junit.runners.model.Statement;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。

package com.bijian.study;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;import org.junit.Assert;import org.junit.ClassRule;import org.junit.Rule;import org.junit.Test;import org.junit.runner.Description;import org.junit.runners.model.Statement;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()),用于指示该测试方法已经执行完毕了。执行结果如下所示:

2014-09-24_00:05:41_375 com.bijian.study.CalculatorTest#simpleDivide: a simple division2014-09-24_00:05:41_375 com.bijian.study.CalculatorTest#simpleDivide end2014-09-24_00:05:41_375 com.bijian.study.CalculatorTest#dividedByZero: divided by zero, and an ArithmeticException thrown.2014-09-24_00:05:41_375 com.bijian.study.CalculatorTest#dividedByZero end

 

3. 小结

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

 

文章来源:http://www.blogjava.net/jiangshachina/archive/2012/01/04/367802.html

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

留言需要登陆哦

技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成

网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];

      订阅博客周刊 去订阅

文章归档

文章标签

友情链接

Auther ·HouTiZong
侯体宗的博客
© 2020 zongscan.com
版权所有ICP证 : 粤ICP备20027696号
PHP交流群 也可以扫右边的二维码
侯体宗的博客