读书人

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

发布时间: 2013-11-18 00:11:49 作者: rapoo

[转]探索JUnit4扩展:深入Rule
转载自:http://www.blogjava.net/jiangshachina/archive/2012/01/04/367802.html探索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[转]探索JUnit4扩充:深入Rule");
????????????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实现,仍然是一种不错的选择。

读书人网 >软件架构设计

热点推荐