从testwather看自定义rule:
原理:实现一个statement,分别在指定位置回调对应的方法(start,success,fail,finish)
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); } } }; }
返回看statement是怎么生成的
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; }
在JUnit执行每个测试方法之前,methodBlock方法都会被调用,用于把该测试包装成一个Statement。Statement代表一个具体的动作,例如测试方法的执行,Before方法的执行或者Rule的调用,类似于J2EE中的Filter,Statement也使用了责任链模式,将Statement层层包裹,就能形成一个完整的测试,JUnit最后会执行这个Statement。从上面代码可以看到,有以下内容被包装进Statement中:
1)测试方法的执行;
2)异常测试,对应于@Test(expected=XXX.class);
3)超时测试,对应与@Test(timeout=XXX);
4)Before方法,对应于@Before注解的方法;
5)After方法,对应于@After注解的方法;
6)Rule的执行。
Junit4 基于自定义Rule的失败重试方案
自定义的也一样,也是实现statement。操作statement,在失败的时候再重跑一遍
testcase class中添加
@Rule public MethodNameExample methodNameExample = new MethodNameExample();
具体实现:
public class MethodNameExample implements TestRule { @Override public Statement apply(final Statement base, final Description description) { return new Statement() { @Override public void evaluate() throws Throwable { try { base.evaluate(); //这其实就是运行测试方法 AutoLog.logs.clear(); } catch (Throwable throwable) { throwable.printStackTrace(); AutoLog.I("当异常的时候发起第二次运行"); base.evaluate(); }
第二种Junit运行下面的RunListener :
public static void main(String[] args) { JUnitCore runner = new JUnitCore(); //Adding listener here runner.addListener(new ExecutionListener()); runner.run(TestFeatureOne.class); } }
RunListener 在onfailed的时候再运行一次test
public class ExecutionListener extends RunListener { /** * Called before any tests have been run. * */ public void testRunStarted(Description description) throws java.lang.Exception { System.out.println("Number of testcases to execute : " + description.testCount()); } /** * Called when all tests have finished * */ public void testRunFinished(Result result) throws java.lang.Exception { System.out.println("Number of testcases executed : " + result.getRunCount()); } /** * Called when an atomic test is about to be started. * */ public void testStarted(Description description) throws java.lang.Exception { System.out.println("Starting execution of test case : "+ description.getMethodName()); } /** * Called when an atomic test has finished, whether the test succeeds or fails. * */ public void testFinished(Description description) throws java.lang.Exception { System.out.println("Finished execution of test case : "+ description.getMethodName()); } /** * Called when an atomic test fails. * */ public void testFailure(Failure failure) throws java.lang.Exception {
System.out.println("Execution of test case failed : "+ failure.getMessage());
TestListenert tt=new TestListenert();
TestResult ttt=new TestResult();
ttt.addListener(tt);
num++;
test.run(ttt);
} /** * Called when a test will not be run, generally because a test method is annotated with Ignore. * */ public void testIgnored(Description description) throws java.lang.Exception { System.out.println("Execution of test case ignored : "+ description.getMethodName()); }