一.需求

ant junitreport 内生的报告中 TestCase 部分,只包含 4 部分:Name, Status, Type, Time(s), 分别代表方法名,运行结果,失败信息,运行时间,如下:
这里写图片描述
但是仅靠 Type 信息(只打印 assertThat 错误信息:期望和实际,错误堆栈),无法确认用例具体的失败,只能回到测试工程重新执行用例,再定位失败原因; 故新增 CASEID 和 CASEDESC 分别描述该用例的 ID 和用例描述,让得到报告第一时间确认是哪块出现问题,缩短排查时间。

二.实现

修改 ant 源码

让 ant 执行 Junit 时,支持用例中自定义注解,需修改源码

新增 TCInfo.java 文件,定义注解@TCInfo

package org.apache.tools.ant.taskdefs.optional.junit;

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

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface TCInfo {
    public String caseId();
    public String caseDesc();
}

修改 XMLJUnitResultFormatter.java 文件,该文件将 Junit 运行结果生成 xml,形如:TEST-完全类名.xml; 新增处理 case 中@TCInfo注解中的信息,输出到 xml 中;

public void endTest(final Test test) {
        final String testDescription = createDescription(test);

        // Fix for bug #5637 - if a junit.extensions.TestSetup is
        // used and throws an exception during setUp then startTest
        // would never have been called
        if (!testStarts.containsKey(testDescription)) {
            startTest(test);
        }
        Element currentTest;
        if (!failedTests.containsKey(test)
                && !skippedTests.containsKey(testDescription)
                && !ignoredTests.containsKey(testDescription)) {
            currentTest = doc.createElement(TESTCASE);
            // hugang, 方法名, name值
            final String n = JUnitVersionHelper.getTestCaseName(test);
            currentTest.setAttribute(ATTR_NAME, n == null ? UNKNOWN : n);
            // a TestSuite can contain Tests from multiple classes,
            // even tests with the same name - disambiguate them.
            // hugang, 类名, classname值
            currentTest.setAttribute(ATTR_CLASSNAME,
                    JUnitVersionHelper.getTestCaseClassName(test));

            // hugang, 生成case info
            Method caseMethod = null;
            Class caseClass = null;
            try{
                // 获取测试类
                caseClass = Class.forName(JUnitVersionHelper.getTestCaseClassName(test));
                // 获取测试方法
                caseMethod = caseClass.getMethod(n, new Class[0]);
            }catch(Exception e){
                e.printStackTrace();
            }
            // 判断测试方法是否有@TCInfo注解
            boolean hasTCInfo = caseMethod.isAnnotationPresent(TCInfo.class);
            if (hasTCInfo) {
                // @TCInfo注解, 则添加case信息
                TCInfo tcInfo = (TCInfo) caseMethod.getAnnotation(TCInfo.class);
                String caseId = tcInfo.caseId();
                String caseDesc = tcInfo.caseDesc();
                currentTest.setAttribute(ATTR_CASEID, caseId);
                currentTest.setAttribute(ATTR_CASEDESC, caseDesc);
            }else{
                // 无@TCInfo, 则默认值
                currentTest.setAttribute(ATTR_CASEID, "无caseid信息");
                currentTest.setAttribute(ATTR_CASEDESC, "无casedesc信息");
            }


            rootElement.appendChild(currentTest);
            testElements.put(createDescription(test), currentTest);

        } else {
            currentTest = testElements.get(testDescription);
        }


        //  case 运行时间
        final Long l = testStarts.get(createDescription(test));
        currentTest.setAttribute(ATTR_TIME, ""
                + ((System.currentTimeMillis() - l) / ONE_SECOND));
    }

可以直接下载工程:https://github.com/neven7/ant.git

打包:在 ant 工程目录下,直接运行 sh build.sh, 在 ant/build/lib 目录下,会生成对应的 jar,我们只需 ant-junit.jar; 将 ant-junit.jar 发布到自己的私有仓库:

mvn deploy:deploy-file -DgroupId=com.weibo -DartifactId=ant-junit -Dversion=0.0.1 -Dpackaging=jar -Durl=http://10.13.1.139:30000/nexus/content/repositories/weiboqa/ -Dfile=/users/hugang/git/ant/build/lib/ant-junit.jar -DrepositoryId=weiboqa -s /Users/hugang/.m2/settings.xml

在测试工程 pom.xml 中依赖该 jar 包

<dependency>
     <groupId>com.weibo.qa</groupId>
     <artifactId>ant-junit</artifactId>
     <version>0.0.1</version>
 </dependency>

在测试用例中新增@TCInfo信息

@TCInfo(caseId="LabTest-01N01", caseDesc="实验测试1")
@Test
public void testSingleExposureBizId() {
   ...
}

使用 ant build.xml 执行用例,生成的 xml 中,新增:casedesc, caseid 信息

<testcase casedesc="实验测试1" caseid="LabTest-01N01" classname="com.weibo.extend.lab.LabTest" name="testSingleExposureBizId" time="7.354">

修改 XSL

ant 使用 XSLT 将 XML 转成 HTML,report 有 2 种形式: "frames" or "noframes"

The frames format uses a stylesheet which is generating output only by redirecting.

The noframes format does not use redirecting and generates one file called junit-noframes.html.

Custom versions of junit-frames.xsl or junit-noframes.xsl must adhere to the above conventions.

分别对应 junit-frames.xsl or junit-noframes.xsl

本文只针对 noframes,故只需修改 junit-noframes.xsl(http://download.csdn.net/download/neven7/9381080),默认 xsl 在 apache-ant-1.9.6/etc 目录下,如需自定义,则需要在 report 指定 styledir 路径,该路径保存自定义的 junit-frames.xsl or junit-noframes.xsl
在执行的 build 中指定自定义 xsl 目录 styedir:

<target name="junitreport" depends="testAll">
                  <junitreport todir="${report}">
                          <fileset dir="${report}/${mytime}">
                                  <include name="TEST-*.xml" />
                          </fileset>
                          <report styledir="/data1/WeTest/junitreport/" format="noframes" todir="${report}/${mytime}" />
                  </junitreport>
</target>

结果展示

根据 XML 通过 XSLT 转换成自定义结果,将@Test中添加了@TCInfo注解的用例描述添加到 report 中

这里写图片描述


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