JUnit4---实践二:拓展之运行指定类的某些测试方法-自动生成该文件
2015-02-02 20:55
465 查看
一.背景
之前介绍过:
JUnit4---实践一:运行指定类的某些测试方法,当重跑用例较少时,可以手工添加指定的测试方法,但是测试方法较多且在多个不同的类时,手工添加就比较头大,有必要自动生成指定测试方法。
想着有2种方法:1.JUnitCore添加监听器RunListener,获得第一次执行的结果,根据结果聚合出指定的测试方法;2.通过扫结果日志,找到FAILED和ERROR,聚合出指定的测试方法。由于项目中是通过ant执行junit和junit-report获得第一次运行结果,自己添加监听器RunListener,不好使,已经尝试过,不成功。如果你是通过JUnitCore运行第一次,可以通过添加监听器RunListener获得FAILED和ERROR。下面介绍具体实现。二.根据结果日志,自动生成测试类
1.在执行ant时,在build.xml中target:junit中添加<formatter type="brief" usefile="true" />,这样会在目标目录下,生成失败用例日志,类似TEST-com.weibo.cases.suite.HugangTestSuite.txt这种的*.txt文件,根据该文件找到失败的测试方法,FindFailTest.java,如下:
package com.weibo.failmethods; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.junit.runner.JUnitCore; import org.junit.runner.Request; import org.junit.runner.Result; /** * @author hugang * 根据日志 找出Failure 和 Error */ public class FindFailTest { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub // 文本每一行 List<String> strList = new ArrayList(); // 行号 List<Integer> flags = new ArrayList(); // 记录FAILED和ERROR Set<String> failSet = new TreeSet(); // String regexStr = // "(Testcase:\\s\\w*([\\w]*.{3,}\\w*.):\\sFAILED)|(Testcase:\\s\\w*([\\w]*.{3,}\\w*.):\\sCaused\\san\\sERROR)"; Pattern p = Pattern.compile("Testcase"); Matcher m; int i = 0; try { Reader re = new FileReader(new File(System.getProperty("user.dir") + "/src/com/weibo/failmethods/" + "TEST-com.weibo.cases.suite.HugangTestSuite.txt")); BufferedReader bre = new BufferedReader(re); while (bre.ready()) { String str = bre.readLine(); strList.add(str); m = p.matcher(str); // 匹配后,记录匹配的行号 if (m.find()) { flags.add(i); System.out.println("find " + i); } i++; } for (int k = 0; k < flags.size(); k++) { // 去除SKIPPED, 只存 FAILED和ERROR if (!strList.get(flags.get(k)).contains("SKIPPED")) { // 从文本中取满足匹配的那行字符串 failSet.add(strList.get(flags.get(k))); } } bre.close(); re.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } Map<String, List<String>> myClassMethodMap = new LinkedHashMap(); List<String> className = new ArrayList<String>(); List<String> methodName = new ArrayList<String>(); for (Iterator it = failSet.iterator(); it.hasNext();) { // System.out.println(it.next().toString()); // Testcase: // testAPIRequest(com.weibo.cases.xuelian.FeedWithDarwinTagsForMovieStatusTest): // FAILED // 取出类和方法 String str = it.next().toString(); int classBegin = str.indexOf("("); int classEnd = str.indexOf(")"); // 类名 String classPart = str.substring(classBegin + 1, classEnd).concat( ".class"); // 方法名, 加上双引号,方便写文件时,注解中方法的添加 String methodPart = "\"" + str.substring(10, classBegin) + "\""; // 聚合 class-method 一对多 if (myClassMethodMap.containsKey(classPart)) { // 拿到之前的class 对应的list, 并在该list下新增 method List<String> methodList = myClassMethodMap.get(classPart); methodList.add(methodPart); myClassMethodMap.put(classPart, methodList); } else { // 第一次添加该class时 List<String> firstMethod = new ArrayList<String>(); firstMethod.add(methodPart); myClassMethodMap.put(classPart, firstMethod); } // className.add(classPart); // methodName.add(methodPart); System.out.println(classPart + " " + methodPart); } System.out.println(className.size()); System.out.println(methodName.size()); System.out.println(myClassMethodMap); new WriteFailTest().writeJavaClass(myClassMethodMap); } }根据获得的失败用例,WriteFailTest.java自动生成测试文件AutoFailMethodsTest.java:
WriteFailTest.java如下:
package com.weibo.failmethods; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.junit.runner.JUnitCore; import org.junit.runner.Request; import org.junit.runner.Result; import com.weibo.failmethods.FailMethodsTest; import com.weibo.failmethods.SuiteClassesMethods; /** * * @author hugang * 直接生成文件 */ public class WriteFailTest { private BufferedWriter writer; public void createClassAnnotation(Map<String, List<String>> myClassMethodMap) throws IOException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss,SSS"); writer.write("//auto java file generated on: "); writer.write(sdf.format(new Date())); writer.newLine(); writer.write("package com.weibo.failmethods;"); writer.newLine(); writer.write("import java.text.SimpleDateFormat;"); writer.newLine(); writer.write("import java.io.*;"); writer.newLine(); writer.write("import java.util.*;"); writer.newLine(); writer.write("import org.junit.runner.*;"); writer.newLine(); writer.write("import com.weibo.cases.hugang.*;"); writer.newLine(); writer.write("import com.weibo.cases.xiaoyu.*;"); writer.newLine(); writer.write("import com.weibo.cases.wanglei16.*;"); writer.newLine(); writer.write("import com.weibo.cases.xuelian.*;"); writer.newLine(); writer.write("import com.weibo.cases.lingna.*;"); writer.newLine(); writer.write("import com.weibo.cases.maincase.*;"); writer.newLine(); String className = ""; String methodsName = ""; String methodsNumPerClass = ""; // 拼接结果 for(Map.Entry<String, List<String>> entry : myClassMethodMap.entrySet()){ className += entry.getKey() + ","; List<String> failMethod = entry.getValue(); for(int m = 0; m < failMethod.size(); m++){ methodsName += failMethod.get(m) + ","; } methodsNumPerClass += failMethod.size() + ","; } System.out.println(className); System.out.println(methodsNumPerClass); System.out.println(methodsName); writer.newLine(); writer.write("@SuiteClassesMethods(className = {"); writer.newLine(); // className.length()-1 去掉最后一个, writer.write(className.substring(0, className.length()-1) + "},"); writer.newLine(); writer.write("methodsNumPerClass = {"); writer.newLine(); writer.write(methodsNumPerClass.substring(0, methodsNumPerClass.length()-1) + "},"); writer.newLine(); writer.write("methodsName = {"); writer.newLine(); writer.write(methodsName.substring(0, methodsName.length()-1) + "})"); } public void createClassBody() throws IOException{ writer.newLine(); writer.write("public class AutoFailMethodsTest {"); writer.newLine(); writer.write(" public static void main(String[] args) throws Exception {"); writer.newLine(); writer.write(" Class<AutoFailMethodsTest> clazz = AutoFailMethodsTest.class;"); writer.newLine(); writer.write(" SuiteClassesMethods scm = clazz.getAnnotation(SuiteClassesMethods.class);"); writer.newLine(); writer.write(" Class<?>[] className = scm.className();"); writer.newLine(); writer.write(" int[] methodsNumPerClass = scm.methodsNumPerClass();"); writer.newLine(); writer.write(" String[] methodsName = scm.methodsName();"); writer.newLine(); writer.write(" Map<Class<?>, List<String>> myClassMethodMap = new LinkedHashMap();"); writer.newLine(); writer.write(" List<List<String>> listMethodsName = new ArrayList<List<String>>();"); writer.newLine(); writer.write(" int k = 0;"); writer.newLine(); writer.write(" for (int i = 0; i < className.length; i++) {"); writer.newLine(); writer.write(" List<String> temp = new ArrayList<String>();"); writer.newLine(); writer.write(" for (int m = 0; m < methodsNumPerClass[i]; m++) {"); writer.newLine(); writer.write(" temp.add(methodsName[k]);"); writer.newLine(); writer.write(" k++;"); writer.newLine(); writer.write(" }"); writer.newLine(); writer.write(" listMethodsName.add(i, temp);"); writer.newLine(); writer.write(" myClassMethodMap.put(className[i], listMethodsName.get(i));"); writer.newLine(); writer.write(" }"); writer.newLine(); writer.write(" JUnitCore junitRunner = new JUnitCore();"); writer.newLine(); writer.write(" List<Result> methodsResult = new ArrayList<Result>();"); writer.newLine(); writer.write(" int failNum = 0;"); writer.newLine(); writer.write(" int successNum = 0;"); writer.newLine(); writer.write(" long runTime = 0L;"); writer.newLine(); writer.write(" for(Map.Entry<Class<?>, List<String>> entry : myClassMethodMap.entrySet()){"); writer.newLine(); writer.write(" Class testClass = entry.getKey();"); writer.newLine(); writer.write(" List<String> failMethod = entry.getValue();"); writer.newLine(); writer.write(" for(int i = 0; i < failMethod.size(); i++){"); writer.newLine(); writer.write(" Request request = Request.method(testClass, failMethod.get(i));"); writer.newLine(); writer.write(" Result result = junitRunner.run(request);"); writer.newLine(); writer.write(" runTime += result.getRunTime();"); writer.newLine(); writer.write(" if(result.wasSuccessful()){"); writer.newLine(); writer.write(" successNum++;"); writer.newLine(); writer.write(" }else{"); writer.newLine(); writer.write(" failNum++;"); writer.newLine(); writer.write(" methodsResult.add(result);"); writer.newLine(); writer.write(" }"); writer.newLine(); writer.write(" } "); writer.newLine(); writer.write(" }"); writer.newLine(); writer.write(" try{"); writer.newLine(); // 记录结果集 , 目录 writer.write(" String filePath = System.getProperty(\"user.dir\") + \"/src/com/weibo/failmethods/Result.txt\";"); writer.newLine(); writer.write(" File file = new File(filePath);"); writer.newLine(); writer.write(" if(!file.exists()){"); writer.newLine(); writer.write(" file.createNewFile();"); writer.newLine(); writer.write(" }"); writer.newLine(); writer.write(" FileOutputStream fop = new FileOutputStream(file);"); writer.newLine(); writer.write(" SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy.MM.dd HH:mm:ss,SSS\");"); writer.newLine(); writer.write(" fop.write(\"## Second Time's Result generated on: \".getBytes());"); writer.newLine(); writer.write(" fop.write(sdf.format(new Date()).getBytes());"); writer.newLine(); writer.write(" fop.write(\"\\n\".getBytes());"); writer.newLine(); writer.write(" StringBuffer sb = new StringBuffer();"); writer.newLine(); writer.write(" sb.append(\"===================== 结果集 =====================\");"); writer.newLine(); writer.write(" sb.append(\"\\n\");"); writer.newLine(); writer.write(" sb.append(\"用例总数:\" + methodsName.length);"); writer.newLine(); writer.write(" sb.append(\", 成功数:\" + successNum);"); writer.newLine(); writer.write(" sb.append(\", 失败数:\" + failNum);"); writer.newLine(); writer.write(" sb.append(\", 运行时间:\" + (runTime/1000)/60 + \" 分钟 \" + (runTime/1000)%60 + \" 秒\");"); writer.newLine(); writer.write(" sb.append(\"\\n\");"); writer.newLine(); writer.write(" sb.append(\"=================================================\");"); writer.newLine(); writer.write(" sb.append(\"\\n\");"); writer.newLine(); writer.write(" sb.append(\"\\n\");"); writer.newLine(); writer.write(" fop.write(sb.toString().getBytes());"); writer.newLine(); writer.write(" for(int j = 0; j < methodsResult.size(); j++){"); writer.newLine(); writer.write(" byte[] fail = methodsResult.get(j).getFailures().toString().getBytes();"); writer.newLine(); writer.write(" fop.write(fail);"); writer.newLine(); writer.write(" fop.write(\"\\n\".getBytes());"); writer.newLine(); writer.write(" fop.write(\"\\n\".getBytes());"); writer.newLine(); writer.write(" }"); writer.newLine(); writer.write(" fop.flush();"); writer.newLine(); writer.write(" fop.close();"); writer.newLine(); writer.write(" }catch(IOException e){"); writer.newLine(); writer.write(" e.printStackTrace();"); writer.newLine(); writer.write(" }"); writer.newLine(); writer.write(" }"); writer.newLine(); writer.write("}"); writer.newLine(); } public void writeJavaClass(Map<String, List<String>> myClassMethodMap) throws IOException { try { File sourceFile = new File(System.getProperty("user.dir") + "/src/com/weibo/failmethods/" + "AutoFailMethodsTest.java"); if (!sourceFile.exists()) { sourceFile.createNewFile(); } if (sourceFile.exists() && !sourceFile.delete()) { throw new IOException("could not delete " + sourceFile); } writer = new BufferedWriter(new FileWriter(sourceFile)); createClassAnnotation(myClassMethodMap); createClassBody(); } catch (IOException e) { e.printStackTrace(); } finally { writer.close(); } } }运行生成的文件:AutoFailMethodsTest.java
得到结果Result.txt:
三.通过JUnitCore添加RunListener,获得失败信息
1.JUnitCore添加RunListener,代码如下:<span style="font-family: Monaco;">package com.weibo.cases.hugang;</span>
import org.junit.Rule; import org.junit.experimental.ParallelComputer; import org.junit.experimental.max.MaxCore; import org.junit.rules.ErrorCollector; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.junit.runner.JUnitCore; import org.junit.runner.Result; import com.weibo.cases.suite.LikeTestSuite; import com.weibo.cases.suite.WangleiTestSuite; public class RetryFailCaseTest { public static void main(String[] args) { JUnitCore core = new JUnitCore(); core.addListener(new MyFailListener()); Result rs = core.run(LikeTestSuite.class); System.out.println(rs.getRunCount() + " " + rs.getRunTime() + " " + rs.getFailureCount()); } }
MyFailListener类为RunListener类的子类,可以自定义一些操作,代码如下:
package com.weibo.cases.hugang; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.util.Set; import java.util.TreeSet; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunListener; public class MyFailListener extends RunListener { public void testFailure(Failure failure) throws IOException{ File failFile = new File("myfail.txt"); if(!failFile.exists()){ failFile.createNewFile(); } try { FileOutputStream fos = new FileOutputStream(failFile, true); fos.write((failure.toString() + "\n").getBytes()); fos.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
自定义监听器MyFailListener将错误信息,写文件,文件内容类似于testObjectsDestroy(com.weibo.cases.xuelian.LikesListBatchLikeTest): object is null!
可以根据错误信息,聚合出失败文件,类似上一节“二.根据结果日志,自动生成测试类”,不再敖述。
相关文章推荐
- JUnit4---实践一:运行指定类的某些测试方法
- 【qtp脚本】实现自动创建目录并通过测试写字板生成指定个数的文件
- Junit4自动生成的测试类的注释中,日期乱码问题解决方法
- 学习使用AutoMake1.9的自动生成工程文件(二)——flat型程序编译实践过程
- spec文件中写上一些脚本,使生成的rpm包在安装前删除系统中指定文件的方法
- 运行QTP测试脚本后,将编译结果写入指定文件(四)
- 附加自动命名的数据库 但失败。已存在同名的数据库 或指定的文件无法打开或位于 unc 共享目录中。【解决方法】
- Junit指定运行的测试方法
- 自动运行xelatex命令两遍及xdvipdfmx生成pdf并删除临时文件的工具
- 自动生成NUnit测试文件
- 删除文件夹下SVN自动生成的文件的一个bat方法
- 运行QTP测试脚本后,将编译结果写入指定文件(二)
- 每次运行都会自动生成****out.xml文件
- 三:理解Page类的运行机制(例:在render方法中生成静态文件)
- 学习使用AutoMake1.9的自动生成工程文件(三)——层叠型加引用静态库工程实践过程
- 第4代白盒测试方法实践之“如何在VcTester集成自动构建功能”
- 自己亲自实践的ant的配置方法和middlegen生成hbmxml文件
- c#自动附加分离备份还原数据库 C#生成安装文件后自动附加数据库的思路跟算法 打包之后,运行之前
- 附加自动命名的数据库,但失败。已存在同名的数据库,或指定的文件无法打开或位于 UNC 共享目录中[解决方法]
- 导入android源码有错,R.java文件不能自动生成解决方法