JUnit4---实践一:运行指定类的某些测试方法

时间:2021-12-26 05:05:49

一.需求(小组内接口自动化由junit4+重试[用例]+HttpClient[调接口,获取数据]+多线程[执行用例]+数据库连接池[测试账号]组成,由ant生成junit报告)

最近,小组内有人提出了,是否能单独运行某些失败的cases,因为在eclipse中只能运行一个类的全部cases或某个cases; 不能指定跑单个类某些方法或多个类的某些方法。juint4中有@RunWith(Suite.class) 和 @Suite.SuiteClasses({A.class, B.class}) 聚合类A和B;但是不能指定某些方法。

在Ant执行Junit中有个formatter(结果的类型type:xmlplainbrief 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();
        }
        
    

    }

}

结果:

JUnit4---实践一:运行指定类的某些测试方法



三.优化输出

由于之前输出结果不太明晰,修改FailMethodsTest.java

package com.weibo.failmethods;
/**
 * @author hugang
 */
//import java.io.File;
//import java.io.FileOutputStream;
//import java.io.IOException;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

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

import com.weibo.cases.hugang.*;


@SuiteClassesMethods(className = { AttitudeRemindTest.class }, methodsNumPerClass = { 1 }, methodsName = {
        "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>();
        // 失败数
        int failNum = 0;
        // 成功数
        int successNum = 0;
        //  运行时间
        long runTime = 0L;
        // 运行测试方法
        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);
                runTime += result.getRunTime();
                // 只添加失败的
                if(result.wasSuccessful()){
                	successNum++;
                }else{
                	failNum++;
                    methodsResult.add(result);
                }
            }
        }
        
//        for(int j = 0; j < methodsResult.size(); j++){
//            methodsResult.get(j).wasSuccessful();
//            methodsResult.get(j).getFailures().toString();
//        }
       
        
        
        // 将错误集记录到file中
        try{
        	String filePath = System.getProperty("user.dir") + "/src/com/weibo/failmethods/failMethods.txt";
        	File file = new File(filePath);
        	if(!file.exists()){
        		file.createNewFile();
        	}
        	FileOutputStream fop = new FileOutputStream(file);
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss,SSS");
			fop.write("// Second Time Result generated on: ".getBytes());
			fop.write(sdf.format(new Date()).getBytes());
			fop.write("\n".getBytes());
			
			StringBuffer sb = new StringBuffer();
			sb.append("===================== 结果集 =====================");
			sb.append("\n");
			sb.append("用例总数:" + methodsName.length);
			sb.append(", 成功数:" + successNum);
			sb.append(", 失败数:" + failNum);
			sb.append(", 运行时间:" + (runTime/1000)/60 + " 分钟 " + (runTime/1000)%60 + " 秒");
			sb.append("\n");
			sb.append("=================================================");
			sb.append("\n");
			sb.append("\n");
			fop.write(sb.toString().getBytes());
			for(int j = 0; j < methodsResult.size(); j++){
				byte[] fail = methodsResult.get(j).getFailures().toString().getBytes();
 				fop.write(fail);
 				fop.write("\n".getBytes());
 				fop.write("\n".getBytes());
 			}
			
			
            
            fop.flush();
            fop.close();
           
        }catch(IOException e){
            e.printStackTrace();
        }
        

    }
    
   

}
输出结果:有结果统计

JUnit4---实践一:运行指定类的某些测试方法


参考:

junit wiki: http://junit.sourceforge.net/javadoc/overview-summary.html