Junit4 基于 custom Rule retry

时间:2021-09-14 05:05:08

从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()); 
}