zoukankan      html  css  js  c++  java
  • 【JUnit4.10源码分析】5.2 Rule


    标注@Rule

    TestRule是一个工厂方法模式中的Creator角色——声明工厂方法。

    package org.junit.rules;
    import org.junit.runner.Description;
    import org.junit.runners.model.Statement;
    public interface TestRule {
    	Statement apply(Statement base, Description description);
    }
    

    因为工厂方法apply有參数base。因而TestRule将创建装饰模式中的装饰对象

    【抽象类Statement声明操作evaluate()的接口。它作为一个回调接口,上层模块能够定义各种Statement的子类。提供evaluate()的方法体。而这一主要的技术与Rule结合,成为JUnit一个很重要的手段——能够说它是一个通用型的复合命令的构造方式。全然能够代替Statement的一些复合命令的子类如ExpectException等。

    測试程序猿要使用Rule,必须编写代码。以下先介绍使用Rule的样例。

    1.MyStatement——Statement的一个新的装饰对象。( JUnit之Rule的使用中的样例),地位等同于ExpectException。

    package rule;
    import static tool.Print.*;//pln(Object)
    import org.junit.runners.model.Statement;
    /**
     *
     * @author yqj2065
     */
    public class MyStatement extends Statement {
        private final Statement base;
        public MyStatement( Statement base ) {
            this.base = base;
        }
    
        @Override public void evaluate() throws Throwable {
            pln( "before...sth..sth" );
            try {
                base.evaluate();
            } finally {
                 pln( "after...sth..sth" );
            }
        }
    }
    2.一个详细的工厂。也就是定义工厂方法的TestRule的子类。MyRule将创建一个Statement的新的装饰对象MyStatement。如同工厂方法模式的一般使用方法,详细工厂与详细产品一一相应。

    package rule;
    import org.junit.rules.TestRule;
    import org.junit.runners.model.Statement;
    import org.junit.runner.Description;
    public class MyRule implements TestRule  {
        @Override
        public Statement apply(Statement base, Description description) {
            return new MyStatement( base );
        }
    }
    3.使用新的装饰对象

    用户类BlockJUnit4ClassRunner使用的是ExpectException等JUnit内建的Statement装饰对象;測试程序猿编写的Statement装饰对象,则须要通过@Rule,嵌入到单元測试类中

    package rule;
    import org.junit.Rule;
    import org.junit.Test;
    public class MyTest {   
        @Rule
        public MyRule myRule = new MyRule();
        
        @Test()
        public void xx() {
            System.out.println( "xx()..." );
        }
    }
    在开发环境中执行MyTest,输出:
    before...sth..sth
    xx()...

    after...sth..sth

    例程 8 17标注Rule
    package org.junit;
    import java.lang.annotation.*;
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface Rule {}
    

    注意:JUnit4.8中Rule标注并没有指定@Target(ElementType.FIELD),而4.10版本号中明白定义出来。Rule用于修饰測试单元类中一个特殊的域。该域必须是public、非static并且是org.junit.rules.TestRule子类型的引用变量(代替4.8版本号的org.junit.rules.MethodRule)。JUnit4.10版本号中还有一个标注@ClassRule,用于修饰測试单元类中static的TestRule子类型的引用变量。


    TestRule

    org.junit.rules.TestRule声明工厂方法,因为工厂方法apply有參数base,因而TestRule将创建装饰模式中的装饰对象。

    然而,装饰对象仍然是一个Statement。

    TestRule的各种实现类创建很多装饰对象。可是没有特别的名字。反正是一个Statement。

    从JUnit框架设计的角度看,TestRule是工厂方法;而从測试程序猿思考问题的角度,TestRule及事实上现类,为单元測试制订了各种附加的规则/Rule。

    在org.junit.rules包中的TestRule的实现类有:

    1. TestWatcher

    对base加以监控的Rule。它不会对结果进行改动。

    TestWatcher以匿名类的方式创建Statement装饰对象。在@Override evaluate()时使用了模板方法模式

    例程 8-4 TestWatchman
    package org.junit.rules;
    
    import org.junit.internal.AssumptionViolatedException;
    import org.junit.runner.Description;
    import org.junit.runners.model.Statement;
    public abstract class TestWatcher implements TestRule {
    	public Statement apply(final Statement base, final Description description) {
    		return new Statement() {
    			@Override
    			public void evaluate() throws Throwable {
    				starting(description);
    				try {
    					base.evaluate();
    					succeeded(description);
    				} catch (AssumptionViolatedException e) {
    					throw e;
    				} catch (Throwable t) {
    					failed(t, description);
    					throw t;
    				} finally {
    					finished(description);
    				}
    			}
    		};
    	}
    	protected void succeeded(Description description) {	}
    	protected void failed(Throwable e, Description description) {	}
    	protected void starting(Description description) {	} 
    	protected void finished(Description description) {	}
    }
    

    TestWatcher的子类TestName是模板方法模式中的详细类角色。

           publicvoid starting(FrameworkMethod method) {

                  fName=method.getName();

           }

    2. Verifier

    使用了模板方法模式,以匿名类的方式创建Statement装饰对象,在base. evaluate()之后加入一个verify()操作。Verifier的子类ErrorCollector收集測试中的错误。

    3. ExpectedException和Timeout

    ExpectedException作为工厂创建装饰对象,其私有内部类ExpectedExceptionStatement全然等价于org.junit.internal.runners.statements.ExpectException的地位。可是,ExpectedException作为规则将作用于各种測试方法。而ExpectException作用于@Test(expected=xxx)修饰的方法

    Timeout则是典型的工厂。返回一个装饰对象FailOnTimeout

    package org.junit.rules;
    import org.junit.internal.runners.statements.FailOnTimeout;
    import org.junit.runner.Description;
    import org.junit.runners.model.Statement;
    
    public class Timeout implements TestRule {
    	private final int fMillis;
    
    	/**
    	 * @param millis the millisecond timeout
    	 */
    	public Timeout(int millis) {
    		fMillis= millis;
    	}
    
    	public Statement apply(Statement base, Description description) {
    		return new FailOnTimeout(base, fMillis);
    	}
    }

    4. ExternalResource

    ExternalResource使用了模板方法模式。以匿名类的方式创建Statement装饰对象。在base. evaluate()之前before()中能够加入各种其它资源(file, socket, server, database connection),而after()中释放资源。其子类TemporaryFolder给出了一个样例。




  • 相关阅读:
    Mysql优化之6年工作经验总结
    mysql_innodb存储引擎的优化
    十六、MySQL授权命令grant的使用方法
    十五、Mysql字符集的那些事
    十四、索引
    十三、视图
    十二、存储过程
    十一、触发器
    十、存储引擎
    九、备份与恢复
  • 原文地址:https://www.cnblogs.com/llguanli/p/6725995.html
Copyright © 2011-2022 走看看