本文提供两种生成测试报告的方法,第一种使用ReportNG,第二种自己重写Report Listener。
一:
先说第一种,使用ReportNG。
1. 首先下载ReportNG的架包,添加到project中。
2. 然后取消使用TestNG默认的监听器,右键工程->Properties->TestNG->勾选Disable default listeners。
3. 然后在testng.xml文件中加入下面内容,规定运行时使用reportng生成report。
<listeners>
<listener class-name="org.uncommons.reportng.HTMLReporter" />
<listener class-name="org.uncommons.reportng.JUnitXMLReporter" />
</listeners>
4. 之后再运行.xml文件时,就会生成类似下面样式的的测试报告了。
二:
接下来介绍第二种重写Report Listener,用htlm拼接生成report。本框架当前采用的是这种方式。
1. 在util包下创建一个class ReportListener,
package util;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;/**
* 生成测试报告.
*/
public class ReportListener extends TestListenerAdapter{
private static String reportPath;
private static int pass = 0;
private static int fail = 0;
private static int skip = 0;
private static int all;
private static float successRate;
private static StringBuilder s1;
private static StringBuilder s2;
private static Date begin;
private static Date finish;
private static long duration;
static List<String> screenshotPaths = new ArrayList<String>();
@Override
public void onStart(ITestContext context) {
File htmlReportDir = new File("test-output/report");
if (!htmlReportDir.exists()) {
htmlReportDir.mkdirs();
}
String reportName = formateDate()+".html";
reportPath = htmlReportDir+"/"+reportName;
File report = new File(htmlReportDir,reportName);
if(report.exists()){
try {
report.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
s1 = new StringBuilder("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />"
+ "<title >UI自动化测试报告</title></head><body>"
+ "<div id=\"top\" align=\"center\"><p style=\"font-weight:bold;font-size:150%\">Test Results Report</p>"
+ "<table width=\"90%\" height=\"80\" border=\"1\" align=\"center\" cellspacing=\"0\" rules=\"all\" style=\"table-layout:relative;\">"
+ "<thead style=\"background-color:#ADD8E6;\">"
+ "<tr>"
+ "<th>Overview</th>"
+ "<th>Tests</th>"
+ "<th>Passed</th>"
+ "<th>Skipped</th>"
+ "<th>Failed</th>"
+ "<th>Success rate</th>"
+ "<th>Duration(s)</th>"
+ "</tr>"
+ "</thead>");
s2 = new StringBuilder("<p style=\"font-weight:bold;\">详情列表</p>"
+ "<table width=\"90%\" height=\"80\" border=\"1\" align=\"center\" cellspacing=\"0\" rules=\"all\" style=\"table-layout:relative;\">"
+ "<thead style=\"background-color:#ADD8E6;\">"
+ "<tr>"
+ "<th>测试用例</th>"
+ "<th>测试用例结果</th>"
+ "<th>Duration(s)</th>"
+ "</tr>"
+ "</thead>"
+ "<tbody style=\"word-wrap:break-word;font-weight:bold;\" align=\"center\">");
begin = new Date();
}
@Override
public void onTestSuccess(ITestResult result) {
StringBuilder sb2 = new StringBuilder("<tr><td align=\"center\">");
sb2.append((result.getMethod().getRealClass()+"."+result.getMethod().getMethodName()).substring(16));
sb2.append("</td><td align=\"center\"><font color=\"green\">Passed</font></td>");
long time =
(result.getEndMillis() - result.getStartMillis())/1000;
sb2.append("</td><td align=\"center\">" + time + "</td></tr>");
s2.append(sb2);
pass = pass+1;
}
@Override
public void onTestSkipped(ITestResult result) {
//加了case失败后冲泡的方法,于是失败的case只有最后一次是faied的状态,前面几次都是skied的状态,所以去掉skipped的报告,这样虽然可能会影响到真正的skipped的case,但是如果保证setup方法不挂掉正常case是不会skipped的
/* StringBuilder sb2 = new StringBuilder("<tr><td align=\"center\">");
sb2.append((result.getMethod().getRealClass()+"."+result.getMethod().getMethodName()).substring(16));
sb2.append("</td><td align=\"center\"><font color=\"#DAA520\">Skipped</font><br>");
sb2.append(result.getMethod().getMethodName());
sb2.append("<p align=\"center\">测试用例<font color=\"red\">跳过</font></p></td>");
long time =
(result.getEndMillis() - result.getStartMillis())/1000;
sb2.append("</td><td align=\"center\">" + time + "</td></tr>");
s2.append(sb2);
skip = skip+1;*/
}
@Override
public void onTestFailure(ITestResult result) {
String error;
try {
StringBuilder sb2 = new StringBuilder("<tr><td align=\"center\">");
sb2.append((result.getMethod().getRealClass()+"."+result.getMethod().getMethodName()).substring(16));
sb2.append("</td><td align=\"center\"><font color=\"red\">Failed</font><br>");
sb2.append(result.getTestName());
sb2.append("<p align=\"center\">用例执行<font color=\"red\">失败</font>,原因:<br>");
sb2.append("<br><a style=\"background-color:#CCCCCC;\">");
Throwable throwable = result.getThrowable();
if(throwable.getMessage().indexOf("Session info")!=-1)
{
int endIndex = throwable.getMessage().indexOf("(Session info");
error = throwable.getMessage().substring(0, endIndex);
}
else
{
error = throwable.getMessage();//断言失败只打印断言
}
sb2.append(error);
sb2.append("</a></p></td>");
long time =
(result.getEndMillis() - result.getStartMillis())/1000;
sb2.append("</td><td align=\"center\">" + time + "</td></tr>");
s2.append(sb2);
fail = fail+1;
String classname = result.getTestClass().getName();
String methodname = result.getMethod().getMethodName();
TakeScreenshot shot = new TakeScreenshot();
String screenshotPath = shot.takeScreenShot(classname, methodname);
screenshotPaths.add(screenshotPath);
}
catch(Exception e) {
//没有Throwable的时候,比如login或logout的时候挂了,exception被catch住了就没有Throwable抛出来
StringBuilder sb2 = new StringBuilder("<tr><td align=\"center\">");
sb2.append((result.getMethod().getRealClass()+"."+result.getMethod().getMethodName()).substring(16));
sb2.append("</td><td align=\"center\"><font color=\"red\">Failed</font><br>");
sb2.append(result.getTestName());
sb2.append("<p align=\"center\">用例执行<font color=\"red\">失败</font>,原因:<br>");
sb2.append("<br><a style=\"background-color:#CCCCCC;\">");
sb2.append(e);
sb2.append("</a></p></td>");
long time =
(result.getEndMillis() - result.getStartMillis())/1000;
sb2.append("</td><td align=\"center\">" + time + "</td></tr>");
s2.append(sb2);
fail = fail+1;
String classname = result.getTestClass().getName();
String methodname = result.getMethod().getMethodName();
TakeScreenshot shot = new TakeScreenshot();
String screenshotPath = shot.takeScreenShot(classname, methodname);
screenshotPaths.add(screenshotPath);
Log4jUtil.error(e);
}
}
@Override
public void onFinish(ITestContext testContext) {
all = fail + pass + skip;
successRate = (float)pass/(float)all*100;
finish = new Date();
duration = (finish.getTime()-begin.getTime())/1000;
StringBuilder sb1 = new StringBuilder("<tbody style=\"word-wrap:break-word;font-weight:bold;\" align=\"center\">"
+ "<tr>"
+ "<td align=\"center\">Smoke</td>"
+ "<td align=\"center\">" + all + "</td>"
+ "<td align=\"center\">" + pass + "</td>"
+ "<td align=\"center\">" + skip + "</td>"
+ "<td align=\"center\">" + fail + "</td>"
+ "<td align=\"center\">" + String.format("%.2f", successRate) + "%" + "</td>"
+ "<td align=\"center\">" + duration + "</td>"
+ "</tr>"
+ "</tbody>"
+ "</table>");StringBuilder sb2 = new StringBuilder("</tbody></table><a href=\"#top\">返回顶部</a></div></body>");
sb2.append("</html>
2. 然后在testng.xml文件中加入下面内容
<listeners>
<listener class-name="util.ReportListener"></listener>
</listeners>
3. 同样要取消使用TestNG默认的监听器,之后再运行.xml文件时,就会生成类似下面样式的的测试报告了。