一.需求(小组内接口自动化由 junit4 cases+ 方法重试 [@Retry]+HttpClient[调接口,获取数据,jackson 反序列化为 java 对象]+ 线程池 [并发执行用例]+ 数据库连接池 [获取测试账号,账号存在 mysql 中] 组成,由 ant 生成 junit 报告)
最近,小组内有人提出了,是否能单独运行某些失败的 cases,因为在 eclipse 中只能运行一个类的全部 cases 或某个 cases; 不能指定跑单个类某些方法或多个类的某些方法。juint4 中有@RunWith(Suite.class) 和 @Suite.SuiteClasses({A.class, B.class}) 聚合类 A 和 B;但是不能指定某些方法。
在 Ant 执行 Junit 中有个 formatter(结果的类型 type:xml, plain, brief or failure),其中 type=failure, collects all failing testXXX() methods and creates a new TestCase which delegates only these failing methods. 我尝试了,执行 ant ***.xml 报错为 substring 空指针,查看源码 FailureRecorder.java; 该文件就是用来创建新的测试类(聚合失败 cases),但是用 Junit3(继承 TestCase),并有 bug,不能用:

public static class TestInfos implements Comparable {
        private final String className;
        private final String methodName;

        public TestInfos(Test test) {
            this.className = test.getClass().getName();
            String _methodName = test.toString();
            this.methodName = _methodName.substring(0, _methodName.indexOf(40));
        }
    ...
}

TestInfos 带参构造函数 TestInfos(Test test) 中
_methodName.substring(0, _methodName.indexOf(40)) // ( 的 ASCII 码:40
_methodName 并没有 ‘(’ 导致空指针。
二.方案
使用注解
@SuiteClassesMethods;指定
Class<?>[] className 类名
int[] methodsNumPerClass(); 每个类对应的方法数量
String[] methodsName() 方法名
实现代码如下:
SuiteClassesMethods.java

package com.weibo.failmethods;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.TYPE})
public @interface SuiteClassesMethods {
    public Class<?>[]  className();
    public int[] methodsNumPerClass();
    public String[] methodsName();
}

FailMethodsTest.java

package com.weibo.failmethods;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
import org.junit.runner.Result;

import com.weibo.cases.hugang.AccountUpdatePrivacyCommentTest;
import com.weibo.cases.hugang.AttitudeRemindTest;

/**
 * @author hugang
 */
@SuiteClassesMethods(className = { AccountUpdatePrivacyCommentTest.class,
        AttitudeRemindTest.class }, methodsNumPerClass = { 2, 1 }, methodsName = {
        "testAllNonAttentionByComment", "testFriendAllAttByComment",
        "testAttitudeSomeOneQunStatusPushCount2" })
public class FailMethodsTest {
    public static void main(String[] args) throws Exception {

        Class<FailMethodsTest> clazz = FailMethodsTest.class;
        SuiteClassesMethods scm = clazz.getAnnotation(SuiteClassesMethods.class);

        Class<?>[] className = scm.className();
        int[] methodsNumPerClass = scm.methodsNumPerClass();
        String[] methodsName = scm.methodsName();

        // 根据注解 传的方法,与每个测试类对应
        Map<Class<?>, List<String>> myClassMethodMap = new LinkedHashMap();

        List<List<String>> listMethodsName = new ArrayList<List<String>>();

        // k游标,遍历methodsName
        int k = 0;
        // 外层for循环,表示类个数
        for (int i = 0; i < className.length; i++) {
            List<String> temp = new ArrayList<String>();
            // 内层for循环,为每个类赋方法
            for (int m = 0; m < methodsNumPerClass[i]; m++) {
                temp.add(methodsName[k]);
                k++;
            }
            listMethodsName.add(i, temp);
            myClassMethodMap.put(className[i], listMethodsName.get(i));

        }

        JUnitCore junitRunner = new JUnitCore();

        List<Result> methodsResult = new ArrayList<Result>();
        // 运行测试方法
        for(Map.Entry<Class<?>, List<String>> entry : myClassMethodMap.entrySet()){
            Class testClass = entry.getKey();
            List<String> failMethod = entry.getValue();
            for(int i = 0; i < failMethod.size(); i++){
                Request request = Request.method(testClass, failMethod.get(i));
                Result result = junitRunner.run(request);
                methodsResult.add(result);
            }
        }

    // 将错误集记录到file中
        try{
            File file = new File("/Users/hugang/Desktop/failMethod.txt");
            FileOutputStream fop = new FileOutputStream(file);
            for(int j = 0; j < methodsResult.size(); j++){
                byte[] fail = methodsResult.get(j).getFailures().toString().getBytes();
                fop.write(fail);
            }

            fop.flush();
            fop.close();

        }catch(IOException e){
            e.printStackTrace();
        }



    }

}

结果:


↙↙↙阅读原文可查看相关链接,并与作者交流