京东质量社区 jmeter 接口自动化测试方案二 (报告优化) 增加 git 路径

taki for 京东 · March 26, 2017 · Last by takaの replied at April 30, 2019 · 5279 hits

通过ant集成Jmeter可以做到生成报告,但是有一些弱点我们去优化下,也可以用xsl去改抽出来模板,这里面没有用模板,直接代码做的,后面有时间拆出模板

我们先看下正常的ant+jmeter教程[超级链接]http://www.cnblogs.com/puresoul/p/4808416.html

这个方案要结合使用,可以看我的上篇文章[超级链接]https://testerhome.com/topics/8114


先看下效果图


ant+jmeter是基于jmeter里面的ant-jmeter-1.1.1.jar 去做的,所以我们可以在这里面加一些自己的东西,其他的执行JTL之类的配置和原来的一样参考[超级链接]http://www.cnblogs.com/puresoul/p/4808416.html

说再多也无用,核心代码如下,这里面依赖几个包如下:jcommon-1.0.16.jar、jfreechart-1.0.13.jar、servlet-api-2.5.jar、jstl-1.2.jar、ant-javamail.jar欢迎大家参考


  • 1.创建一个可以供ant执行的类,我们也需要和原来的配置一样加一些东西进去,这里加了ReportTask,下面所有的类都可以直接扔到ant-jmeter-1.1.1.jar里
<target name="reportTask">
<taskdef name="myReportTask" classname="org.programmerplanet.ant.taskdefs.jmeter.ReportTask" />
<myReportTask in="${jmeter.result.jtlName}"
out="${jmeter.result.htmlName}"
mailhost="smtp.qq.com"
ssl="true"
user="qq号"
password="授权密码"
mailTitle="接口测试报告"
from="qq@qq.com"
toAddress="qq@qq.com"
runUser="写执行人的名字">
</myReportTask>
</target>

因为是通过ant命令行执行的,所以日志信息我用System.out输出的,ReportTask 里面的属性和xml里面一致

package org.programmerplanet.ant.taskdefs.jmeter;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

import java.io.File;
import java.util.List;

/**
* Created with IntelliJ IDEA.
* User: jiaou
* Date: 16-11-7
* Time: 下午12:52
* To change this template use File | Settings | File Templates.
*/

public class ReportTask extends Task {
private String in;
private String out;
private String mailhost;
private String mailport;
private boolean ssl;
private String user;
private String password;
private String mailTitle;
private String from;
private String toAddress;
private String runUser;

/**
* @see Task#execute()
*/

public void execute() throws BuildException {
System.out.println("开始执行收集报告任务");
if (null == in || in.equals("")) {
System.out.println("in,Jtl文件不能为空!");
return;
}
if (null == out || out.equals("")) {
System.out.println("out,输出目录不能为空!");
return;
}
File directory = new File(out);
String outputPath = "";
try {
outputPath = directory.getParent();
} catch (Exception e) {
System.out.println("获取输出文件路径异常,请确认输入的是正确的文件路径");
e.printStackTrace();
return;
}
String mailContent = "";
try {
//读取JTL文件获取所用的用例
List<ReportCase> reportCaseList = Report.getReportList(in);
//把所有用例写入html文件
Report.writeReport(reportCaseList,0,out,runUser);
String pngPath = outputPath + "\\report.png";
//生成通过率撸片
Report.writePng(pngPath);
//获取邮件正文
mailContent = MailReport.reportHtml(Report.allCase, Report.passCase, Report.runTime, runUser);
} catch (Exception e) {
e.printStackTrace();
return;
}
System.out.println("报告和图片生成完成,开始发送邮件");
//smtp.qq.com
MailObj mailObj = new MailObj();
mailObj.setHost(mailhost);
mailObj.setPort(mailport);
mailObj.setMailTitle(mailTitle);
mailObj.setName(user);
mailObj.setPassword(password);
mailObj.setFrom(from);
mailObj.setToAddress(toAddress);
mailObj.setSsl(ssl);
mailObj.setMailContent(mailContent);
mailObj.setReportPath(outputPath);
mailObj.setHtmlPath(out);
try {
SendEmail.sendEmail(mailObj);
} catch (Exception e) {
System.out.println("发送邮件失败:" + e);
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}

}

public void setIn(String in) {
this.in = in;
}

public void setOut(String out) {
this.out = out;
}

public void setMailhost(String mailhost) {
this.mailhost = mailhost;
}

public void setMailport(String mailport) {
this.mailport = mailport;
}

public void setSsl(boolean ssl) {
this.ssl = ssl;
}

public void setUser(String user) {
this.user = user;
}

public void setPassword(String password) {
this.password = password;
}

public void setMailTitle(String mailTitle) {
this.mailTitle = mailTitle;
}

public void setFrom(String from) {
this.from = from;
}

public void setToAddress(String toAddress) {
this.toAddress = toAddress;
}

public String getIn() {
return in;
}

public String getOut() {
return out;
}

public String getMailhost() {
return mailhost;
}

public String getMailport() {
return mailport;
}

public boolean isSsl() {
return ssl;
}

public String getUser() {
return user;
}

public String getPassword() {
return password;
}

public String getMailTitle() {
return mailTitle;
}

public String getFrom() {
return from;
}

public String getToAddress() {
return toAddress;
}

public String getRunUser() {
return runUser;
}

public void setRunUser(String runUser) {
this.runUser = runUser;
}
}


  • 2.接下来是用于读取JTL文件生成HTML文件的类,我都加了注释了
package org.programmerplanet.ant.taskdefs.jmeter;


import org.jfree.data.general.DefaultPieDataset;
import org.w3c.dom.*;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;

/**
* Created with IntelliJ IDEA.
* User: jiaou
* Date: 16-7-23
* Time: 上午10:51
* To change this template use File | Settings | File Templates.
*/

public class Report {
public static int allCase = 0;
public static int passCase = 0;
public static int caseNum = 0;
public static long runTime = 0;
private static NumberFormat numberFormat = NumberFormat.getInstance();

/*
* @Description:读取JTL生成报告文件,转换成List
* @param:jtl文件路径
* @return:list对象
* */

public static List<ReportCase> getReportList(String jtlPath) throws Exception {
System.out.println("开始读取JTL文件,路径:" + jtlPath);
Document document = null;
DocumentBuilder documentBuilder = null;
File file = new File(jtlPath);
try {
DocumentBuilderFactory factory = null;
factory = DocumentBuilderFactory.newInstance();
documentBuilder = factory.newDocumentBuilder();
document = documentBuilder.parse(file);
} catch (Exception e) {
System.out.println("转换JTL文件失败,请确认JTL格式是否正确:" + e);
throw new Exception(e);
}
System.out.println("读取JTL文件完毕,开始获取测试用例:");
Element element = document.getDocumentElement();
NodeList nodeList = element.getChildNodes();
List<ReportCase> reportCaseList = new ArrayList<ReportCase>();
long startTime = 0;
long endTime = 0;
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
String nodeName = node.getNodeName();
if (nodeName.contains("Sample")) {
ReportCase reportCase = new ReportCase();
NamedNodeMap namedNodeMap = node.getAttributes();
try {
//获取测试用例名称
Node lb = namedNodeMap.getNamedItem("lb");
String caseName = lb.getNodeValue();
reportCase.setCaseName(caseName);

//获取运行时间
Node runTimeNode = namedNodeMap.getNamedItem("t");
if (!isEmpty(runTimeNode)) {
reportCase.setRunTime(runTimeNode.getNodeValue() + "ms");
}
//获取code码
Node responseCodeNode = namedNodeMap.getNamedItem("rc");
if (!isEmpty(responseCodeNode)) {
reportCase.setResponseCode(responseCodeNode.getNodeValue());
}
//获取responseMessage
Node responseMessageNode = namedNodeMap.getNamedItem("rm");
if (!isEmpty(responseMessageNode)) {
reportCase.setResponseMessage(responseMessageNode.getNodeValue());
}
//获取开始时间
Node startTimeNode = namedNodeMap.getNamedItem("ts");
if (!isEmpty(startTimeNode)) {
String startTimeStr = startTimeNode.getNodeValue();
if (allCase == 0) {
startTime = Long.parseLong(startTimeStr);
}
if (i == nodeList.getLength() - 1) {
endTime = Long.parseLong(startTimeStr);
}
}
//获取是否执行成功
Node statusNode = namedNodeMap.getNamedItem("s");
if (!isEmpty(statusNode)) {
String s = statusNode.getNodeValue();
boolean status = Boolean.parseBoolean(s);
reportCase.setStatus(status);
}
//获取断言对象
Node assertionNode = getNodeByName(node, "assertionResult");
if (!isEmpty(assertionNode)) {
AssertionResult assertionResult = formatAssertion(assertionNode);
reportCase.setAssertionResult(assertionResult);
} else {
reportCase.setAssertionResult(null);
}
//获取响应数据
Node responseDataNode = getNodeByName(node, "responseData");
if (!isEmpty(responseDataNode)) {
reportCase.setResponseData(responseDataNode.getTextContent());
}
//获取方法名称
Node methodNode = getNodeByName(node, "method");
if (!isEmpty(methodNode)) {
reportCase.setMethodName(methodNode.getTextContent());
}
//获取入参
Node queryStringNode = getNodeByName(node, "queryString");
if (!isEmpty(queryStringNode)) {
reportCase.setQueryString(queryStringNode.getTextContent());
}
//获取接口名
Node urlNode = getNodeByName(node, "java.net.URL");
if (!isEmpty(urlNode)) {
reportCase.setUrl(urlNode.getTextContent());
}
} catch (Exception e) {
e.printStackTrace();
}
allCase++;
reportCaseList.add(reportCase);
}
}
if (endTime - startTime > 1000) {
runTime = (endTime - startTime) / 1000;
} else {
runTime = 1;
}
System.out.println("用例转换完毕");
return reportCaseList;
}
/*
* @Description:判断是否为空
* @param:Object o
* @return:boolean
* */

private static boolean isEmpty(Object o) {
boolean f = false;
if (o == null) {
f = true;
}
return f;
}

/*
* @Description:将断言结果转换成对象
* @param:node对象
* @return:断言对象
* */

private static AssertionResult formatAssertion(Node assertionNode) {
AssertionResult assertionResult = new AssertionResult();
Node nameNode = getNodeByName(assertionNode, "name");
assertionResult.setName(nameNode.getTextContent());
Node failureNode = getNodeByName(assertionNode, "failure");
boolean failure = Boolean.parseBoolean(failureNode.getTextContent());
assertionResult.setFailure(failure);
Node errorNode = getNodeByName(assertionNode, "error");
boolean error = Boolean.parseBoolean(errorNode.getTextContent());
assertionResult.setError(error);
Node failureMessageNode = getNodeByName(assertionNode, "failureMessage");
if (!isEmpty(failureMessageNode)) {
assertionResult.setFailureMessage(failureMessageNode.getTextContent());
}
return assertionResult;
}

/*
* @Description:通过名字获取节点
* @param:node,name
* @return:Node
* */

public static Node getNodeByName(Node node, String name) {
NodeList msgNodeList = node.getChildNodes();
Node node1 = null;
for (int k = 0; k < msgNodeList.getLength(); k++) {
Node childNode = msgNodeList.item(k);
String childName = childNode.getNodeName();
if (childName.equalsIgnoreCase(name)) {
node1 = childNode;
break;
}
}
return node1;
}

/*
* @Description:输出图片
* @param:输出图片路径
* @return:
* */

public static void writePng(String pngPath) {
System.out.println("开始生成饼状图!!!");
try {
DefaultPieDataset dataSet = new DefaultPieDataset();
String casePassCount = passCase + "";
String caseFailCount = (allCase - passCase) + "";
dataSet.setValue("PassCase", new Double(casePassCount));
dataSet.setValue("FailCase", new Double(caseFailCount));
PicReport picReport = new PicReport();
picReport.save(dataSet, pngPath, "通过率");
System.out.println("饼状图生成结束,路径:" + pngPath);
} catch (Exception e) {
System.out.println("饼状图生成失败:" + e);
}
}
/*
* @Description:生成html报告文件
* @param:测试用例集合,运行时间,输出路径,执行人
* @return:
* */

public static void writeReport(List<ReportCase> reportCaseList, long runTime, String htmlPath, String runUser) {
String title = getTitle() + getBodyTitle();
String suiteBody = getSuiteList(reportCaseList) + getCaseStep(reportCaseList) + htmlEnd();
String summary = getSummary(runTime, runUser);
String html = title + summary + suiteBody;
try {
File htmlPathFile = new File(htmlPath);
String pathParent = htmlPathFile.getParent();
File parentFile = new File(pathParent);
if (!parentFile.exists()) {
parentFile.mkdirs();
}
} catch (Exception e) {
e.printStackTrace();
}
FileUtil.writeFile(htmlPath, html);
System.out.println("写入Html文件结束!!!");
}

private static String getTitle() {
return getHeadStart() + ReportStyle.getStyle() + ReportJavaScript.getJavaScript() + getHeadEnd();
}
/*
* @Description:生成html报告文件
* @param:测试用例集合,运行时间,输出路径,执行人
* @return:
* */

private static String getBodyTitle() {
String reportName = "接口自动化测试报告";
String date = DateUtil.getCurrentDate();
String bodyTitle = "<body><h1>" + reportName + "</h1>" +
"<table width=\"100%\">" +
" <tr>" +
" <td align=\"left\">Date report: " + date + "</td>" +
" <td align=\"right\">Designed for use with <a href=\"#\">longteng</a> and <a href=\"#\">贾鸥</a>.</td>" +
" </tr>" +
"</table>";
return bodyTitle;
}

/*
* @Description:获取概要的内容
* @param:运行时间,执行人
* @return:
* */

private static String getSummary(long runTimeLong, String runUser) {
int failCase = allCase - passCase;
String passRate = numberFormat.format((float) passCase / (float) allCase * 100) + "%"; //通过率
String runTime = runTimeLong + "秒";
String ip = OS.getLocalIP();
String summary = "" +
"<hr size=\"1\">" +
"<h2>概要</h2>" +
"<table align=\"center\" class=\"summary\" >" +
" <tr valign=\"top\">" +
" <th>用例总数</th>" +
" <th>通过数</th>" +
" <th>失败数</th>" +
" <th>通过率</th>" +
" <th>运行时间</th>" +
" <th>执行机器IP</th>" +
" <th>执行人</th>" +
" </tr>" +
" <tr valign=\"top\" class=\"\">" +
" <td align=\"center\">" + allCase + "</td>" +
" <td align=\"center\">" +
" <span style=\"color: green\">" +
" <b>" + passCase + "</b>" +
" </span>" +
" </td>" +
" <td align=\"center\">" +
" <span style=\"color: red\">" +
" <b>" + failCase + "</b>" +
" </span></td>" +
" <td align=\"center\">" + passRate + "</td>" +
" <td align=\"center\">" + runTime + "</td>" +
" <td align=\"center\">" + ip + "</td>" +
" <td align=\"center\">" + runUser + "</td>" +
" </tr>" +
"</table>" +
"</br>";
return summary;
}
/*
* @Description:获取左侧菜单用例集
* @param:reportCaseList
* @return:str
* */

private static String getSuiteList(List<ReportCase> reportCaseList) {
String menuStr = "<hr size=\"1\" width=\"100%\" align=\"center\">" +
"<div>" +
" <div id=\"div_left\" style=\"overflow:auto\">" +
" <table id=\"suites\">";
String suites = "";
int i = 0;
String suiteName = "用例列表";
String tbodyId = "tests-" + i;
String toggleId = "toggle-" + i;
suites += "<thead>" +
" <tr>" +
" <th class=\"header suite\" onclick=\"toggleElement('" + tbodyId + "', 'table-row-group'); toggle('" + toggleId + "')\">" +
" <span id=\"" + toggleId + "\" class=\"toggle\">&#x25bc;</span>" +
" <span id=\"" + i + "\">" + suiteName + "</span>" +
" </th>" +
" </tr>" +
" </thead>";
String suiteCase = getCaseList(tbodyId, reportCaseList);
suites += suiteCase;
String center = "<div id=\"div_center\">" +
" </div>";
menuStr = menuStr + suites + " </table></div>" + center;
return menuStr;
}
/*
* @Description:获取左侧菜单用例集
* @param:reportCaseList
* @return:str
* */

private static String getCaseList(String tbodyId, List<ReportCase> caseList) {
String tBody = "<tbody id=\"" + tbodyId + "\" class=\"tests\">";
String div = "<div id=\"allSpan\" style=\"display:none\">";
for (int i = 0; i < caseList.size(); i++) {
ReportCase reportCase = caseList.get(i);
String caseName = reportCase.getCaseName();
boolean caseStatus = reportCase.isStatus();
tBody += "<tr><td class=\"test\">";
allCase++;
div += "<div>";
if (caseStatus) {
passCase++;
tBody += " <span class=\"successIndicator\" title=\"全部通过\">&#x2714;</span>";
div += " <span class=\"successIndicator\" title=\"全部通过\">&#x2714;</span>";
} else {
tBody += " <span class=\"failureIndicator\" title=\"部分失败\">&#x2718;</span>";
div += " <span class=\"failureIndicator\" title=\"部分失败\">&#x2718;</span>";
}
tBody += " <a id=\"Case" + caseNum + "\" href=\"#\" onclick=\"showDetail(this)\">" + caseName + "</a>" +
" </td>" +
" </tr>";
div += "<a href=\"#\" onclick=\"showDetail(this)\">" + caseName + "</a>";
div += "</div>";
caseNum++;
}
div += "</div>";
tBody += div;
tBody += "</tbody>";
return tBody;
}

/*
* @Description:获取报告正文
* @param:reportCaseList
* @return:str
* */

private static String getCaseStep(List<ReportCase> reportCaseList) {
String div = "<div id=\"div_right\" style=\"overflow:auto\">";
div += "<ol id=\"right-panel\">\n";
caseNum = 0;
String caseDiv = "";
String firstCaseName = "";
String step = "";
for (int k = 0; k < reportCaseList.size(); k++) {
ReportCase reportCase = reportCaseList.get(k);
String caseName = reportCase.getCaseName();
String display = "none";
if (caseNum == 0) {
display = "";
firstCaseName = caseName;
}
step += "<div id =\"parentCase" + caseNum + "\" style=\"display: " + display + "\">";
step += caseDetail(reportCase);
step += "</div>";
caseNum++;
}
caseDiv = caseDiv + step;
div += "<table>" +
"<tr>" +
"<td><h1 id =\"caseName\">当前用例:" + firstCaseName + "</h1></td>" +
"<td>\n" +
" &nbsp;&nbsp;&nbsp;&nbsp;\n" +
"</td>\n" +
"<td>\n" +
" <h1>用例状态类型:</h1>\n" +
"</td>\n" +
"<td>\n" +
" <select onchange=\"showCaseType(this)\">\n" +
" <option value=\"all\" selected=\"selected\">全部用例</option>\n" +
" <option value=\"successIndicator\">通过用例</option>\n" +
" <option value=\"failureIndicator\">失败用例</option>\n" +
" </select>\n" +
"</td>\n" +
"<td>\n" +
" &nbsp;&nbsp;&nbsp;&nbsp;\n" +
"</td>\n" +
"<td>\n" +
" <input id=\"searchText\" type=\"text\">\n" +
" <button onclick=\"searchCase()\">搜索用例</button>\n" +
"</td></tr>" +
"</table>";
div += caseDiv;
div += "<input id=\"allCaseNum\" type=\"hidden\" value=\"" + caseNum + "\">" +
" <input id=\"currentCaseId\" type=\"hidden\" value=\"parentCase0\">" +
"</div></div></ol>";
return div;
}
/*
* @Description:获取用例详细信息
* @param:reportCaseList
* @return:str
* */

private static String caseDetail(ReportCase reportCase) {
AssertionResult assertionResult = reportCase.getAssertionResult();
String div = "<div class=\"group\">Sampler</div>\n" +
"<div class=\"zebra\">\n" +
"<table>\n" +
"<tr><td class=\"data key\">Time</td><td class=\"data delimiter\">:</td><td class=\"data\">" + reportCase.getRunTime() + "</td></tr>\n" +
"<tr><td class=\"data key\">Response Code</td><td class=\"data delimiter\">:</td><td class=\"data\">" + reportCase.getResponseCode() + "</td></tr>\n" +
"<tr><td class=\"data key\">Response Message</td><td class=\"data delimiter\">:</td><td class=\"data\">" + reportCase.getResponseMessage() + "</td></tr>\n" +
"</table>\n" +
"</div>\n";
if (null != assertionResult) {
if (assertionResult.isFailure() || assertionResult.isError()) {
div += "<div class=\"trail\"></div>\n" +
"<div class=\"group\">Assertion</div>\n" +
"<div class=\"zebra\">\n" +
"<table>\n" +
"<tbody class=\"failure\"><tr><td class=\"data assertion\" colspan=\"3\">" + assertionResult.getName() + "</td></tr>\n" +
"<tr><td class=\"data key\">Failure</td><td class=\"data delimiter\">:</td><td class=\"data\">" + assertionResult.isFailure() + "</td></tr>\n" +
"<tr><td class=\"data key\">Error</td><td class=\"data delimiter\">:</td><td class=\"data\">" + assertionResult.isError() + "</td></tr>\n" +
"<tr><td class=\"data key\">Failure Message</td><td class=\"data delimiter\">:</td>\n" +
"<td class=\"data\">" + assertionResult.getFailureMessage() + "</td></tr></tbody></table></div>\n";
;
}
}
div += "<div class=\"trail\">\n" +
"</div><div class=\"group\">Request</div>\n" +
"<div class=\"zebra\">" +
"<table>" +
"<tr><td class=\"data key\">接口/Url</td><td class=\"data delimiter\">:</td><td class=\"data\"><pre class=\"data\">" + reportCase.getUrl() + "</pre></td></tr>" +
"<tr><td class=\"data key\">Method</td><td class=\"data delimiter\">:</td><td class=\"data\"><pre class=\"data\">" + reportCase.getMethodName() + "</pre></td></tr>" +
"<tr><td class=\"data key\">Query String</td><td class=\"data delimiter\">:</td><td class=\"data\"><pre class=\"data\">" + reportCase.getQueryString() + "</pre></td></tr>\n" +
"</table>\n" +
"</div>\n" +
"<div class=\"trail\"></div>\n" +
"<div class=\"group\">Response</div><div class=\"zebra\">\n" +
"<table>\n" +
"<tr><td class=\"data key\">Response Data</td><td class=\"data delimiter\">:</td><td class=\"data\">\n" +
"<pre class=\"data\">" + reportCase.getResponseData() + "</pre></td></tr>\n" +
"</table>\n" +
"</div>\n";
return div;
}


private static String getHeadStart() {
String title = "<!DOCTYPE html private \"-//W3C//DTD HTML 4.01 Transitional//EN\">" +
"<html>" +
"<head>" +
" <META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">" +
" <title>Load Test Results</title>";

return title;
}
private static String htmlEnd() {
return "</div></div></body></html>";
}
private static String getHeadEnd() {
return "</head>";
}

}


  • 3.生成饼状图的类
package org.programmerplanet.ant.taskdefs.jmeter;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot3D;
import org.jfree.chart.servlet.ServletUtilities;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.general.DefaultPieDataset;


import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;

/**
* Created with IntelliJ IDEA.
* User: jiaou
* Date: 14-5-5
* Time: 下午11:05
* To change this template use File | Settings | File Templates.
*/

public class PicReport extends ServletUtilities {
/**
* 饼状图
*/

public static void pieChart3D(DefaultPieDataset dataset, String fileName, String titleName) {
JFreeChart chart = ChartFactory.createPieChart3D(titleName, dataset,
true, true, false);
PiePlot3D plot = (PiePlot3D) chart.getPlot();
plot.setSectionPaint("FailCase", Color.RED);
plot.setSectionPaint("PassCase", Color.green);

// 图片中显示百分比:默认方式
// plot.setLabelGenerator(new
// StandardPieSectionLabelGenerator(StandardPieToolTipGenerator.DEFAULT_TOOLTIP_FORMAT));
// 图片中显示百分比:自定义方式,{0} 表示选项, {1} 表示数值, {2} 表示所占比例 ,小数点后两位
plot.setLabelGenerator(new StandardPieSectionLabelGenerator(
"{0}({2})", NumberFormat.getNumberInstance(),
new DecimalFormat("0.00%")));
// 图例显示百分比:自定义方式, {0} 表示选项, {1} 表示数值, {2} 表示所占比例
plot.setLegendLabelGenerator(new StandardPieSectionLabelGenerator(
"{0}={1}({2})"));
// 设置背景色为白色
chart.setBackgroundPaint(Color.white);
// 指定图片的透明度(0.0-1.0)
plot.setForegroundAlpha(1.0f);
// 指定显示的饼图上圆形(false)还椭圆形(true)
plot.setCircular(true);
// 设置图标题的字体
Font font = new Font(" 黑体", Font.CENTER_BASELINE, 20);
TextTitle title = new TextTitle(titleName);
title.setFont(font);
chart.setTitle(title);
plot.setLabelFont(new Font("SimSun", 0, 15));//
LegendTitle legend = chart.getLegend(0);
legend.setItemFont(new Font("宋体", Font.BOLD, 16));
try {
ChartUtilities.saveChartAsJPEG(
new File(fileName), //输出到哪个输出流
1, //JPEG图片的质量,0~1之间
chart, //统计图标对象
640, //宽
300,//宽
null //ChartRenderingInfo 信息
);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
public void save(DefaultPieDataset dataset, String fileName, String titleName) {
pieChart3D(dataset, fileName, titleName);
}
}


  • 4.邮件正文
package org.programmerplanet.ant.taskdefs.jmeter;


import java.text.NumberFormat;

/**
* Created with IntelliJ IDEA.
* User: jiaou
* Date: 16-7-23
* Time: 下午10:51
* To change this template use File | Settings | File Templates.
*/

public class MailReport {
private static NumberFormat numberFormat = NumberFormat.getInstance();
/**
* 获取发送邮件的征文
* @return String
*/

public static String reportHtml(int allCase,int passCase,long runTime,String user) {
String ip = OS.getLocalIP();
int failCase = allCase - passCase;
String passRate = numberFormat.format((float) passCase / (float) allCase * 100) + "%"; //通过率
String h = "<TABLE Align='center' width=1000px>\n" +
" <TR>\n" +
" <TD Align='center'>\n" +
" <span style='font-family:微软雅黑;font-size:42px;font-weight:normal;font-style:italic;text-decoration:none;color:#31c5ff;'><strong>自动化测试报告</strong></span>\n" +
" </TD>\n" +
" </TR>\n" +
"</table>\n" +
"<div>\n" +
" <hr size=\"1\" width=\"90%\">\n" +
" <TABLE Align='center' class=\"details\" border=0 cellpadding=5 cellspacing=2 width=85%>\n" +
" <tr>\n" +
" <td>\n" +
" <h1>概要</h1>\n" +
" </td>\n" +
" <Td colspan=\"6\"></Td>\n" +
" </tr>\n" +
" <tr valign=\"top\">\n" +
" <th style=\" color: #ffffff;font-weight: bold;text-align: center;background: #2674a6;white-space: nowrap;\">\n" +
" 用例总数\n" +
" </th>\n" +
" <th style=\" color: #ffffff;font-weight: bold;text-align: center;background: #2674a6;white-space: nowrap;\">\n" +
" 通过数\n" +
" </th>\n" +
" <th style=\" color: #ffffff;font-weight: bold;text-align: center;background: #2674a6;white-space: nowrap;\">\n" +
" 失败数\n" +
" </th>\n" +
" <th style=\" color: #ffffff;font-weight: bold;text-align: center;background: #2674a6;white-space: nowrap;\">\n" +
" 通过率\n" +
" </th>\n" +
" <th style=\" color: #ffffff;font-weight: bold;text-align: center;background: #2674a6;white-space: nowrap;\">\n" +
" 运行时间\n" +
" </th>\n" +
" <th style=\" color: #ffffff;font-weight: bold;text-align: center;background: #2674a6;white-space: nowrap;\">\n" +
" 执行机器IP\n" +
" </th>\n" +
" <th style=\" color: #ffffff;font-weight: bold;text-align: center;background: #2674a6;white-space: nowrap;\">\n" +
" 执行人\n" +
" </th>\n" +
" </tr>\n" +
" <tr valign=\"top\" class=\"Failure\">\n" +
" <td align=\"center\" style=\"background: #eeeee0;white-space: nowrap;\">" + allCase + "</td>\n" +
" <td align=\"center\" style=\"background: #eeeee0;white-space: nowrap;\"><span style =\"color: green;\">" + passCase + "</span></td>\n" +
" <td align=\"center\" style=\"background: #eeeee0;white-space: nowrap;\"><span style =\"color: red;\">" + failCase + "</span></td>\n" +
" <td align=\"center\" style=\"background: #eeeee0;white-space: nowrap;\">" + passRate + "</td>\n" +
" <td align=\"center\" style=\"background: #eeeee0;white-space: nowrap;\">" + runTime + "秒</td>\n" +
" <td align=\"center\" style=\"background: #eeeee0;white-space: nowrap;\">" + ip + "</td>\n" +
" <td align=\"center\" style=\"background: #eeeee0;white-space: nowrap;\">" + user + "</td>\n" +
" </tr>\n" +
"\n" +
" </table>\n";
String detail =
" <TABLE Align='center' class=\"details\" border=0 cellpadding=5 cellspacing=2 width=80%>\n" +
" <tr>\n" +
" <td>\n" +
" <h1>详细</h1>\n" +
" </td>\n" +
" <Td colspan=\"6\"></Td>\n" +
" </tr>\n" +
" <tr valign=\"top\">\n" +
" <th style=\" color: #ffffff;font-weight: bold;text-align: center;background: #2674a6;white-space: nowrap;\">\n" +
" 测试场景\n" +
" </th>\n" +
" <th style=\" color: #ffffff;font-weight: bold;text-align: center;background: #2674a6;white-space: nowrap;\">\n" +
" 用例数量\n" +
" </th>\n" +
" <th style=\" color: #ffffff;font-weight: bold;text-align: center;background: #2674a6;white-space: nowrap;\">\n" +
" 通过用例\n" +
" </th>\n" +
" <th style=\" color: #ffffff;font-weight: bold;text-align: center;background: #2674a6;white-space: nowrap;\">\n" +
" 失败用例\n" +
" </th>\n" +
" <th style=\" color: #ffffff;font-weight: bold;text-align: center;background: #2674a6;white-space: nowrap;\">\n" +
" 通过率\n" +
" </th>\n" +
" </tr>\n" +
" <tr valign=\"top\" class=\"Failure\">\n" +
" <td align=\"center\" style=\"background: #eeeee0;white-space: nowrap;\">22</td>\n" +
" <td align=\"center\" style=\"background: #eeeee0;white-space: nowrap;\">7</td>\n" +
" <td align=\"center\" style=\"background: #eeeee0;white-space: nowrap;\">68.18%</td>\n" +
" <td align=\"center\" style=\"background: #eeeee0;white-space: nowrap;\">25 ms</td>\n" +
" <td align=\"center\" style=\"background: #eeeee0;white-space: nowrap;\">NaN</td>\n" +
" </tr>\n" +
" </table>\n" +
"</div></br>";
h = h + "<TABLE Align='center' width=600px >\n" +
"<tr> <td>" +
"<h1></h1></td></tr>" +
" <tr>" +
" <td Align='center'>\n" +
" <img src='cid:passRate'' width=800 height=400 Align='center' alt=''>\n" +
" </td>\n" +
" </tr>\n" +
"</table>\n";
return h;
}
}



  • 5.css样式的类,样式我没有抽取出来直接放在代码里面了,弄模板还没有直接调来的快
package org.programmerplanet.ant.taskdefs.jmeter;

/**
* Created by jiaou on 2016/12/26.
*/

public class ReportStyle {

public static String getStyle() {
String style = "<style type=\"text/css\">\n" +
" /*概body的基本样式*/\n" +
" body {\n" +
" font: normal 68% verdana, arial, helvetica;\n" +
" color: #000000;\n" +
" }\n" +
"\n" +
" /*概要表格的样式开始*/\n" +
" table tr td, table tr th {\n" +
" font-size: 68%;\n" +
" }\n" +
"\n" +
" table.summary {\n" +
" border: 0;\n" +
" cellpadding: 5;\n" +
" cellspacing: 2;\n" +
" width: 95%;\n" +
" }\n" +
"\n" +
" table.summary tr th {\n" +
" color: #ffffff;\n" +
" font-weight: bold;\n" +
" text-align: center;\n" +
" background: #2674a6;\n" +
" white-space: nowrap;\n" +
" }\n" +
"\n" +
" table.summary tr td {\n" +
" background: #eeeee0;\n" +
" white-space: nowrap;\n" +
" }\n" +
"\n" +
" /*概要表格的样式结束*/\n" +
"\n" +
" /*标题样式结束*/\n" +
" h1 {\n" +
" margin: 0px 0px 5px;\n" +
" font: 165% verdana, arial, helvetica\n" +
" }\n" +
"\n" +
" h2 {\n" +
" margin-top: 1em;\n" +
" margin-bottom: 0.5em;\n" +
" font: bold 125% verdana, arial, helvetica\n" +
" }\n" +
"\n" +
" /*标题样式结束*/\n" +
"\n" +
" /*左侧用例列表的样式*/\n" +
" #div_left {\n" +
" float: left;\n" +
" width: 15%;\n" +
" height: 100%;\n" +
" }\n" +
"\n" +
" .suite {\n" +
" background-color: #999999;\n" +
" font-weight: bold;\n" +
" }\n" +
"\n" +
" #suites {\n" +
" line-height: 1.7em;\n" +
" border-spacing: 0.1em;\n" +
" width: 100%;\n" +
" }\n" +
"\n" +
" .header {\n" +
" font-size: 1.0em;\n" +
" font-weight: bold;\n" +
" text-align: left;\n" +
" }\n" +
"\n" +
" .header.suite {\n" +
" cursor: pointer;\n" +
" clear: right;\n" +
" height: 1.214em;\n" +
" margin-top: 1px;\n" +
" }\n" +
"\n" +
" .toggle {\n" +
" font-family: monospace;\n" +
" font-weight: bold;\n" +
" padding-left: 2px;\n" +
" padding-right: 5px;\n" +
" color: #777777;\n" +
" }\n" +
"\n" +
" .test {\n" +
" background-color: #eeeeee;\n" +
" padding-left: 2em;\n" +
" }\n" +
"\n" +
" .successIndicator {\n" +
" float: right;\n" +
" font-family: monospace;\n" +
" font-weight: bold;\n" +
" padding-right: 2px;\n" +
" color: #44aa44;\n" +
" }\n" +
"\n" +
" .skipIndicator {\n" +
" float: right;\n" +
" font-family: monospace;\n" +
" font-weight: bold;\n" +
" padding-right: 2px;\n" +
" color: #ffaa00;\n" +
" }\n" +
"\n" +
" .failureIndicator {\n" +
" float: right;\n" +
" font-family: monospace;\n" +
" font-weight: bold;\n" +
" padding-right: 2px;\n" +
" color: #ff4444;\n" +
" }\n" +
"\n" +
" /*左侧用例列表的样式结束*/\n" +
"\n" +
" /*中间DIV样式*/\n" +
" #div_center {\n" +
" float: left;\n" +
" width: 2%;\n" +
" height: 100%;\n" +
" }\n" +
"\n" +
" /*右侧报告正文的样式*/\n" +
" #div_right {\n" +
" float: left;\n" +
" width: 83%;\n" +
" height: 100%;\n" +
" }\n" +
"\n" +
" #right-panel {\n" +
" margin-left: -40;\n" +
" right: 0;\n" +
" top: 0;\n" +
" bottom: 0;\n" +
" left: 11px;\n" +
" overflow: auto;\n" +
" background: white\n" +
" }\n" +
"\n" +
" #right-panel .group {\n" +
" font-size: 15px;\n" +
" font-weight: bold;\n" +
" line-height: 16px;\n" +
" padding: 0 0 0 18px;\n" +
" counter-reset: assertion;\n" +
" background-repeat: repeat-x;\n" +
" background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAQCAYAAADXnxW3AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDEBUkDq8pxjkAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAADdJREFUCNdVxrERwDAMAzGK0v47eS6Z927SpMFBAAbkvSvnRk5+7K5cVfLMyN39bWakJAjA5xw9R94jN3tVhVEAAAAASUVORK5CYII=)\n" +
" }\n" +
"\n" +
" #right-panel .zebra {\n" +
" background-repeat: repeat;\n" +
" padding: 0 0 0 18px;\n" +
" background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAmCAYAAAAFvPEHAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDEBYWFlNztEcAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAABdJREFUCNdjYKAtePv5338mBgYGBpoQAGy1BAJlb/y6AAAAAElFTkSuQmCC)\n" +
" }\n" +
"\n" +
" #right-panel .data {\n" +
" line-height: 19px;\n" +
" white-space: nowrap\n" +
" }\n" +
"\n" +
" #right-panel pre.data {\n" +
" white-space: pre\n" +
" }\n" +
"\n" +
" #right-panel tbody.failure {\n" +
" color: red\n" +
" }\n" +
"\n" +
" #right-panel td.key {\n" +
" min-width: 108px\n" +
" }\n" +
"\n" +
" #right-panel td.delimiter {\n" +
" min-width: 18px\n" +
" }\n" +
"\n" +
"\n" +
" .arguments {\n" +
" font-family: Lucida Console, Monaco, Courier New, monospace;\n" +
" font-weight: bold;\n" +
" }\n" +
" </style>\n";
return style;
}
}



  • 6.javaScript的类
package org.programmerplanet.ant.taskdefs.jmeter;

/**
* Created by jiaou on 2016/12/26.
*/

public class ReportJavaScript {
public static String getJavaScript() {
String javaScript = "<script language=\"JavaScript\">\n" +
" /*\n" +
" * 展开关闭左侧用例列表方法\n" +
" * */\n" +
" function toggleElement(elementId, displayStyle) {\n" +
" var current = getStyle(elementId, 'display');\n" +
" document.getElementById(elementId).style.display = (current == 'none' ? displayStyle : 'none');\n" +
" }\n" +
" function getStyle(elementId, property) {\n" +
" var element = document.getElementById(elementId);\n" +
" return element.currentStyle ? element.currentStyle[property] : document.defaultView.getComputedStyle(element, null).getPropertyValue(property);\n" +
" }\n" +
"\n" +
"\n" +
" function toggle(toggleId) {\n" +
" var toggle;\n" +
" if (document.getElementById) {\n" +
" toggle = document.getElementById(toggleId);\n" +
" } else if (document.all) {\n" +
" toggle = document.all[toggleId];\n" +
" }\n" +
" toggle.textContent = toggle.innerHTML == '\\u25b6' ? '\\u25bc' : '\\u25b6';\n" +
" }\n" +
" /*\n" +
" * 删除左面菜单所有子元素\n" +
" * */\n" +
" function deleteAllTestBody(testTbody) {\n" +
" var trArray = testTbody.childNodes;\n" +
" var length = trArray.length;\n" +
" for (var i = 0; i < length; i++) {\n" +
" try {\n" +
" var nodeName = trArray[i].nodeName;\n" +
" if (nodeName == \"TR\") {\n" +
" testTbody.removeChild(trArray[i]);\n" +
" }\n" +
" } catch (e) {\n" +
"\n" +
" }\n" +
" }\n" +
" }\n" +
" /*\n" +
" * 根据状态显示当前的用例\n" +
" * */\n" +
" function showCaseType(obj) {\n" +
" var status = \"successIndicator\";\n" +
" status = obj.value;\n" +
" var testTbody = document.getElementById(\"tests-0\");\n" +
" deleteAllTestBody(testTbody);\n" +
" var allSpan = document.getElementById(\"allSpan\");\n" +
" var spanDivList = allSpan.getElementsByTagName(\"div\");\n" +
" var htmlTr = \"\";\n" +
" var index = 0;\n" +
" for (var i = 0; i < spanDivList.length; i++) {\n" +
" var div = spanDivList[i];\n" +
" try {\n" +
" var span = div.getElementsByTagName(\"span\")[0];\n" +
" var a = div.getElementsByTagName(\"a\")[0];\n" +
" a.setAttribute(\"id\", \"Case\" + index);\n" +
" var spanOuterHTML = span.outerHTML;\n" +
" var aOuterHTML = a.outerHTML;\n" +
" if (status == \"all\") {\n" +
" htmlTr += \"<tr><Td class='test'>\" + spanOuterHTML + aOuterHTML + \"</Td></tr>\"\n" +
" } else {\n" +
" var spanClassName = span.className;\n" +
" if (status == spanClassName) {\n" +
" htmlTr += \"<tr><Td class='test'>\" + spanOuterHTML + aOuterHTML + \"</Td></tr>\"\n" +
" }\n" +
" }\n" +
" index++;\n" +
" } catch (E) {\n" +
"\n" +
" }\n" +
" }\n" +
" testTbody.innerHTML = htmlTr;\n" +
" }\n" +
" /*\n" +
" * 根据用例名称查询测试用例\n" +
" * */\n" +
" function searchCase() {\n" +
" var searchText = document.getElementById(\"searchText\").value;\n" +
" var table = document.getElementById(\"suites\");\n" +
" var aList = table.getElementsByTagName(\"a\");\n" +
" if (aList.length > 0) {\n" +
" var index = 0;\n" +
" for (var i = 0; i < aList.length; i++) {\n" +
" var obj = aList[i];\n" +
" var text = obj.text;\n" +
" if (searchText == text) {\n" +
" showDetail(obj);\n" +
" break;\n" +
" }\n" +
" console.info(text);\n" +
" index++;\n" +
" }\n" +
" if (index == aList.length) {\n" +
" alert(\"当前状态下没有该用例\")\n" +
" }\n" +
" }\n" +
" }\n" +
" /*\n" +
" * 点击左侧用例按钮显示当前用例到正文\n" +
" * */\n" +
" function showDetail(obj) {\n" +
" var caseId = obj.id;\n" +
" document.getElementById(\"currentCaseId\").value = caseId;\n" +
" var caseName = obj.text;\n" +
" document.getElementById(\"caseName\").innerHTML = \"当前用例:\" + caseName;\n" +
" var parentCaseId = \"parent\" + caseId;\n" +
" var allCaseNum = document.getElementById(\"allCaseNum\").value;\n" +
" for (var i = 0; i < allCaseNum; i++) {\n" +
" var div = \"parentCase\" + i;\n" +
" if (div == parentCaseId) {\n" +
" document.getElementById(div).style.display = \"inline\"\n" +
" } else {\n" +
" document.getElementById(div).style.display = \"none\"\n" +
" }\n" +
" }\n" +
" }\n" +
" </script>";

return javaScript;
}
}


  • 7.邮件的类
package org.programmerplanet.ant.taskdefs.jmeter;

import com.sun.mail.util.MailSSLSocketFactory;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
* Created with IntelliJ IDEA.
* User: jiaou
* Date: 14-8-19
* Time: 下午2:55
* To change this template use File | Settings | File Templates.
*/

public class SendEmail {
// private static Logger logger = Logger.getLogger(SendEmail.class);

// JavaMail需要Properties来创建一个session对象。它将寻找字符串"mail.smtp.host",属性值就是发送邮件的主机
public static void sendEmail(MailObj mailObj) throws Exception {
Properties properties = new Properties();

// 开启debug调试
// properties.setProperty("mail.debug", "true");
// 发送服务器需要身份验证
properties.setProperty("mail.smtp.auth", Boolean.toString(mailObj.isSsl()));
// 设置邮件服务器主机名
properties.setProperty("mail.host", mailObj.getHost());
// 发送服务器端口
if (mailObj.getPort() != null && !mailObj.getPort().equalsIgnoreCase("")) {
properties.setProperty("mail.smtp.port", mailObj.getPort());
}
// 发送邮件协议名称
properties.setProperty("mail.transport.protocol", "smtp");

//开启了 SSL 加密 QQ邮箱要加上
if (mailObj.getFrom().endsWith("@qq.com")) {
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.ssl.socketFactory", sf);
}
final String userName = mailObj.getName();
final String password = mailObj.getPassword();
/*
* 在 JavaMail 中,可以通过 extends Authenticator 抽象类,在子类中覆盖父类中的
* getPasswordAuthentication() 方法,就可以实现以不同的方式来进行登录邮箱时的用户身份认证。JavaMail
* 中的这种设计是使用了策略模式(Strategy
*/

MimeMessage message = new MimeMessage(Session.getInstance(properties,
new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(//设置发送帐号密码
userName, password);
}
}));
// 设置邮件的属性

// 设置邮件的发件人
message.setFrom(new InternetAddress(mailObj.getFrom()));

String sendTo = mailObj.getToAddress();
String sendToCC = mailObj.getToCc();

// 设置邮件的收件人 cc表示抄送 bcc 表示暗送
if (null != sendTo) {
InternetAddress[] senderList = new InternetAddress()
.parse(sendTo);
message.setRecipients(Message.RecipientType.TO, senderList);
} else {
return;
}
if (null != sendToCC) {
InternetAddress[] iaCCList = new InternetAddress()
.parse(sendToCC);
message.setRecipients(Message.RecipientType.CC, iaCCList);
}
String subject = mailObj.getMailTitle();
if (subject.equalsIgnoreCase("")) {
// 设置邮件的主题
message.setSubject("自动化测试报告");
} else {
message.setSubject(subject);
}

// 创建邮件的正文
MimeBodyPart text = new MimeBodyPart();
// setContent(“邮件的正文内容”,”设置邮件内容的编码方式”)
text.setContent(mailObj.getMailContent() + "<img src='cid:b'>",
"text/html;charset=UTF-8");

// 点到点的发送
// 一对多发送只要改一个地方如下:


// 创建图片
MimeBodyPart img = new MimeBodyPart();
/*
* JavaMail API不限制信息只为文本,任何形式的信息都可能作茧自缚MimeMessage的一部分.
* 除了文本信息,作为文件附件包含在电子邮件信息的一部分是很普遍的. JavaMail
* API通过使用DataHandler对象,提供一个允许我们包含非文本BodyPart对象的简便方法.
*/




// 关系 正文和图片的
MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(text);

// 创建图片的一个表示用于显示在邮件中显示
File pngFile = new File(mailObj.getReportPath() + "\\report.png");
if (pngFile.exists()) {
DataHandler dh = new DataHandler(new FileDataSource(pngFile.getAbsolutePath()));//图片路径
img.setDataHandler(dh);
img.setContentID("passRate");
mm.addBodyPart(img);
}
// mm.addBodyPart(img2);
mm.setSubType("related");// 设置正文与图片之间的关系

// 创建附件
File file = new File(mailObj.getHtmlPath());
if (file.exists()) {
MimeBodyPart attch = new MimeBodyPart();
DataHandler dh1 = new DataHandler(new FileDataSource(file.getAbsolutePath()));
attch.setDataHandler(dh1);
String filename1 = dh1.getName();
// MimeUtility 是一个工具类,encodeText()//用于处理附件字,防止中文乱码问题
attch.setFileName(MimeUtility.encodeText(filename1));
mm.addBodyPart(attch);
}

// 图班与正文的 body
MimeBodyPart all = new MimeBodyPart();
all.setContent(mm);
// 附件与正文(text 和 img)的关系
MimeMultipart mm2 = new MimeMultipart();
mm2.addBodyPart(all);
mm2.setSubType("mixed");// 设置正文与附件之间的关系

// mm3.setSubType("related");// 设置正文与图片之间的关系
message.setContent(mm);
message.saveChanges(); // 保存修改

Transport.send(message);// 发送邮件
// logger.info("邮件发送成功");
System.out.println("邮件发送成功");
}
}


  • 8.断言的类
package org.programmerplanet.ant.taskdefs.jmeter;

/**
* Created with IntelliJ IDEA.
* User: jiaou
* Date: 16-11-7
* Time: 下午2:35
* To change this template use File | Settings | File Templates.
*/

public class AssertionResult {
private String name;
private boolean failure;
private boolean error;
private String failureMessage;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public boolean isFailure() {
return failure;
}

public void setFailure(boolean failure) {
this.failure = failure;
}

public boolean isError() {
return error;
}

public void setError(boolean error) {
this.error = error;
}

public String getFailureMessage() {
return failureMessage;
}

public void setFailureMessage(String failureMessage) {
this.failureMessage = failureMessage;
}
}


  • 9.OS类,用于获取IP
package org.programmerplanet.ant.taskdefs.jmeter;

import java.awt.*;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

/**
* Created with IntelliJ IDEA.
* User: jiaou
* Date: 16-7-23
* Time: 下午10:51
* To change this template use File | Settings | File Templates.
*/

public class OS {
public static final int LINUX = 1;
public static final int WINDOWS = 0;
public static boolean runModeBaseBS = false;

private static boolean osIsMacOsX;
private static boolean osIsWindows;
private static boolean osIsWindowsXP;
private static boolean osIsWindows2003;
private static boolean osIsLinux;
public static String fileSeparator = System.getProperty("file.separator");

public static void initOS() {
String os = System.getProperty("os.name").toLowerCase();
osIsMacOsX = "mac os x".equals(os);
osIsWindows = os.indexOf("windows") != -1;
osIsWindowsXP = "windows xp".equals(os);
osIsWindows2003 = "windows 2003".equals(os);
osIsLinux = "linux".equalsIgnoreCase(os);
}


/**
* 获取本机IP
*/

public static String getLocalIP() {
initOS();
String ip = "";
try {
if (isLinux()) {
Enumeration<?> e1 = (Enumeration<?>) NetworkInterface
.getNetworkInterfaces();
while (e1.hasMoreElements()) {
NetworkInterface ni = (NetworkInterface) e1.nextElement();
if (!ni.getName().equals("eth0")) {
continue;
} else {
Enumeration<?> e2 = ni.getInetAddresses();
while (e2.hasMoreElements()) {
InetAddress ia = (InetAddress) e2.nextElement();
if (ia instanceof Inet6Address)
continue;
ip = ia.getHostAddress();
}
break;
}
}
} else {
ip = InetAddress.getLocalHost().getHostAddress().toString();
}

} catch (Exception e) {
e.printStackTrace();
}
if(ip==null||ip.equalsIgnoreCase("")){
ip=getCentOsIp();
}
return ip;
}
}
共收到 29 条回复 时间 点赞

这貌似改的工程有点大?我之前是直接在持续集成系统里发邮件的,然后加一个xsl,除了生成最终报告多一个生成html片段(测试概要)的子任务,引入到邮件内容中,明天电脑上看看

taki #2 · March 26, 2017 作者
北溟 回复

用xsl也可以弄,我没抽出来模板

taki #3 · March 26, 2017 作者
北溟 回复

抽出来模板有些东西也要重写的

不错不错

—— 来自TesterHome官方 安卓客户端

内容挺不错的,小小建议下,代码建议还是放关键部分即可,如果确实想给出比较完整的代码,更建议放到 github 然后文末给个链接查看。否则代码太多,容易看不清文章的层级。

taki #6 · March 27, 2017 作者
陈恒捷 回复

嗯,有github一直没用,后续再有东西放到git上

Baozhida jmeter+ant+jenkins 接口自动化报告模版 中提及了此贴 27 Mar 17:10

核心代码太核心,复制之后,还少很多东西

能否发我一份完整的源码或者jar包么,感谢!
qqmail :280745188@qq.com

同求完整的jar包 QQ869091814

建议楼主 将这些 html内容放到一个静态模板文件里面,然后把需要每次替换的数据变成 关键字,再每次读取出来根据关键字再replace。

能不能把代码放到 github 然后给个链接查看,我们也好参考详细完整代码

楼主没有考虑过 使用 jmeter + maven 的方式吗? github有写好的插件

lz 想问一下1 jar的包不是编译好的嘛不能再修改代码了吧
那么你怎么去修改ant-jmeter-1.1.1.jar这个文件的?

taki #15 · May 16, 2017 作者
ice 回复

源码重新编译

taki 回复

谢了 不过我发现这玩意直接有源代码 不过藏得很隐蔽。。。还是给我找到了

不好意思啊 问一下 MailObj这个类是哪来的?javamail和ant-javamail里好像没有

List 这个类 和 isLinux() 这个方法好像也没有

请教下我把代码导入进去了,但是几个class都存在报错。
1)SendEmail.java有很多报错,不晓得是不是jar包版本不匹配;
2)ReportTask.java和Report.java里的ReportCase 不存在报错;
3)OS.java里的isLinux()方法 不存在报错;

楼主能帮忙解答下这些问题吗?估计很多想进行报告优化的同学都遇到过这些问题。如果其他同学有解决过这些问题,请指点下:
85628284@qq.com

taki 回复

谢谢楼主开源 不过我已经自己把剩下的代码补齐了 还是谢谢啦

taki 回复

我按照你的思路,自己用javamail写的发邮件

非常感谢楼主开源,我已经调通成功可以发送邮件和生产报告。
但是生成的HTML报告在各种浏览器上打开都是空白的,点击刷新能看到报告页面数据,但仅仅也是一闪而过又变成空白的了😭
楼主之前有遇到过这个问题吗?

taki #24 · June 30, 2017 作者
ben liao 回复

没有,先看本地是否能正确打开

LZ的报告上,运行时间是负的,这个问题有解决么?
有没有考虑,在搜索框中检索出耗时比较长的用例

sendmai 类的 导入 MailSSLSocketFactory报错怎么解决...

运行那个类都是提示找不到 org.programmerplanet.ant.taskdefs.jmeter.** 楼主知道是什么原因么

taki #29 · November 23, 2018 作者
回复

少包

taki #30 · November 23, 2018 作者
isenven 回复

暂时没有,呵呵,这个做的属于演示性质,没做那么完善

isenven 回复

遍历httpSample节点取start time和endtime时 修改一下就可以了

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up