接口测试 Jmeter+ant+Jenkins 接口自动化框架完整版

grizz · May 09, 2018 · Last by 轱辘 replied at April 09, 2019 · 6924 hits

一、背景

上一篇讲了Jmeter 接口自动化-脚本数据分离实例,我们知道怎么利用Jmeter去编写接口自动化脚本,但是接口自动化测试单有脚本是不够的,我们还需要批量跑指定接口,生成接口运行报告,定位报错接口,接口定时任务,邮件通知等功能。
批量跑指定接口:我们可以利用ant批量跑指定目录下的Jmeter脚本
生成接口运行报告:使用Jmeter(extras目录下)自带的jmeter-results-detail-report_21.xsl样式文件
定位报错接口:使用扩展的jmeter-results-shanhe-me.xsl(可自行下载,我git地址也放了)样式文件,输出的信息比自带的jmeter-results-detail-report_21.xsl
接口定时任务:使用Jenkins的build periodically完成
邮件通知:使用Jenkins的Extended E-mail Notification插件

顺序从Jmeter-》Jmeter+ant-》Jmeter+ant+Jenkins穿插原理,逐渐过渡,二中讲的是基础(可跳过),三讲的是实践,遇到的问题以及扩展。

二、Jmeter+ant+Jenkins接口自动化框架搭建

1 Jmeter

1、E:\sample下有sample.jmx的脚本文件
2、追加E:\apache-jmeter-2.13\bin到path环境变量后
环境变量配置成功验证-》dos中输入jmeter,windows会直接打开jmeter
3、Dos命令:
cd /d e:
cd sample
jmeter -n -t sample.jmx -l log.jtl

-n 这是指定JMeter在非用户界面模式运行
-t 包含测试计划的JMX文件的名字
-l 记录取样结果的JTL文件的名字

这里要讲两句,我们做接口自动化还好,要是用Jmeter做负载测试时,建议写好性能脚本后,用NON GUI模式进行负载测试,即非图形化界面,也就是建议使用命令行运行!因为图形化界面会消耗资源,导致负载测试结果不精确,特别是用图形化界面时还把查看结果树给打开,查看结果树输出的结果很多,所以,写完负载测试脚本后尽量把查看结果树等调试插件给禁掉
我们启动Jmeter3.0以上版本,也有建议不要使用图形化界面进行负载测试的提示:
翻译:不要使用GUI模式进行负载测试,只用于测试创建和测试调试!

2 Jmeter+ant

1、下载ant后在window中设置ant环境变量:
ANT_HOME 新建:E:\Program Files\apache-ant-1.7.1
path 追加:%ANT_HOME%\bin
环境变量配置成功验证-》dos中输入ant,提示:Buildfile: build.xml does not exist!

2、将JMeter所在目录下extras子目录里的ant-JMeter-1.1.1.jar复制到Ant所在目录lib子目录之下,这样Ant运行时才能找到"org.programmerplanet.ant.taskdefs.jmeter.JMeterTask"这个类,从而成功触发JMeter脚本

3、jmeter默认保存的是.csv格式的文件,所以我们先要设置一下bin/jmeter.properties文件内容,保存
jmeter.save.saveservice.output_format=xml
4、主要逻辑思路:
E:\jmeter\build下有build_smoke_report.xml文件
运行E:\jmeter\script_smoke下面的.jmx脚本,生成.jtl文件放入 E:\jmeter\report_smoke文件中
然后ant再利用指定的.xsl文件(build_smoke_report.xml定义)去解析.jtl文件,生成对应的html文件放入E:\jmeter\report_smoke中。
简写就是:跑完结果后,.xsl文件把.jtl文件转化成直观的html报告。

PS:XSL是什么
XSL是可扩展样式表语言(eXtensible Stylesheet Language)的外语缩写,是一种用于以可读格式呈现 XML(标准通用标记语言的子集)数据的语言。
易懂一点的说法:XSL可描述如何来显示 XML 文档,XSL 之于XML,就像CSS之于HTML。

build_smoke_report.xml文件中的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project name="ant-jmeter-test" default="run" basedir=".">
<tstamp>
<format property="time" pattern="_yyyy_MMdd_HHmmss" />
</tstamp>
<!-- 需要改成自己本地的 Jmeter 目录-->
<property name="jmeter.home" value="E:\apache-jmeter-2.13" />
<property name="report.title" value="接口测试"/>
<!-- jmeter生成jtl格式的结果报告的路径-->
<property name="jmeter.result.jtl.dir" value="E:\jmeter\report_smoke" />
<!-- jmeter生成html格式的结果报告的路径-->
<property name="jmeter.result.html.dir" value="E:\jmeter\report_smoke" />
<property name="detail" value="_detail" />
<!-- 生成的报告的前缀-->
<property name="ReportName" value="SmokeReport" />
<property name="jmeter.result.jtlName" value="${jmeter.result.jtl.dir}/${ReportName}${time}.jtl" />
<property name="jmeter.result.htmlName" value="${jmeter.result.html.dir}/${ReportName}${time}.html" />

<target name="run">
<antcall target="test" />
<antcall target="report" />
</target>

<target name="test">
<taskdef name="jmeter" classname="org.programmerplanet.ant.taskdefs.jmeter.JMeterTask" />
<jmeter jmeterhome="${jmeter.home}" resultlog="${jmeter.result.jtlName}">
<!-- 声明要运行的脚本"*.jmx"指包含此目录下的所有jmeter脚本-->
<testplans dir="E:\jmeter\script_smoke" includes="*.jmx" />

<property name="jmeter.save.saveservice.output_format" value="xml"/>
</jmeter>
</target>

<path id="xslt.classpath">
<fileset dir="${jmeter.home}/lib" includes="xalan*.jar"/>
<fileset dir="${jmeter.home}/lib" includes="serializer*.jar"/>
</path>


<target name="report">
<tstamp> <format property="report.datestamp" pattern="yyyy/MM/dd HH:mm" /></tstamp>
<xslt
classpathref="xslt.classpath"
force="true"
in="${jmeter.result.jtlName}"
out="${jmeter.result.htmlName}"
style="${jmeter.home}/extras/jmeter-results-detail-report_21.xsl">
<param name="dateReport" expression="${report.datestamp}"/>
</xslt>
<!-- 因为上面生成报告的时候,不会将相关的图片也一起拷贝至目标目录,所以,需要手动拷贝 -->
<copy todir="${jmeter.result.html.dir}">
<fileset dir="${jmeter.home}/extras">
<include name="collapse.png" />
<include name="expand.png" />
</fileset>
</copy>
</target>

</project>

Dos切换到E:\jmeter\build目录下运行:ant –f build_smoke_report.xml
提示:BUILD SUCCESSFUL代表build_smoke_report.xml文件运行成功
E:\jmeter\script_smoke目录下会生成.jtl和.html文件

3 Jmeter+ant+Jenkins

1、 命令行切换到jenkins.war的根目录,输入 java -jar jenkins.war
2、 浏览器输入地址http://localhost:8080显示界面,安装成功

3、新建一个构建自由风格的软件项目并配置

4、设置定时任务,这里是设置每周一到周五的8点30分运行次JOB。
定时构建语法:

  • * * * * *(五颗星,中间用空格隔开)

第一颗*表示分钟,取值0~59
第二颗*表示小时,取值0~23
第三颗*表示一个月的第几天,取值1~31
第四颗*表示第几月,取值1~12
第五颗*表示一周中的第几天,取值0~7,其中0和7代表的都是周日

4、构建->增加构建步骤->Invoke Ant->高级(需要去Jenkins的系统配置->Global Tool Configuration配置ant的地址),Build File中输入E:\jmeter\build\build_smoke_report.xml,保存

5、立即构建,运行成功,查看console output控制台输入的日志
出现BUILD SUCCESSFUL表示编译成功,跟dos运行ant –f build_smoke_report.xml效果一样

三、扩展的分割线

1·执行多个目录的jmx脚本


<jmeter jmeterhome="${jmeter.home}" resultlog="${jmeter.result.jtlName}">
<!-- 声明要运行的脚本"*.jmx"指包含此目录下的所有jmeter脚本-->
<testplans dir="E:\jmeter\script_smoke" includes="*.jmx" />

<property name="jmeter.save.saveservice.output_format" value="xml"/>
</jmeter>

改成


<jmeter jmeterhome="${jmeter.home}" resultlog="${jmeter.result.jtlName}">
<!-- 声明要运行的脚本"*.jmx"指包含此目录下的所有jmeter脚本-->
<testplans dir="E:\jmeter\script_smoke" includes="*.jmx" />
<testplans dir="E:\jmeter\script_smoke_two" includes="*.jmx" />

<property name="jmeter.save.saveservice.output_format" value="xml"/>
</jmeter>

2.生成多个html报告

我这里是生成两个,一个简单的汇总报告,一个详细的报告(用于定位接口报错)
build_smoke_report.xml文件只利用jmeter-results-detail-report_21.xsl生成了一个html报告,想利用jmeter-results-shanhe-me.xsl生成第二个
添加属性值


<property name="detail" value="_detail" />
<property name="jmeter.result.jtlNamedetail" value="${jmeter.result.jtl.dir}/${ReportName}${time}.jtl" />
<property name="jmeter.result.htmlNamedetail" value="${jmeter.result.html.dir}/${ReportName}${time}${detail}.html" />

并且将


<target name="report">
<tstamp> <format property="report.datestamp" pattern="yyyy/MM/dd HH:mm" /></tstamp>
<xslt
classpathref="xslt.classpath"
force="true"
in="${jmeter.result.jtlNamedetail}"
out="${jmeter.result.htmlNamedetail}"
style="${jmeter.home}/extras/jmeter-results-shanhe-me.xsl">
<param name="dateReport" expression="${report.datestamp}"/>
</xslt>

改为


<target name="report">
<tstamp> <format property="report.datestamp" pattern="yyyy/MM/dd HH:mm" /></tstamp>
<xslt
classpathref="xslt.classpath"
force="true"
in="${jmeter.result.jtlName}"
out="${jmeter.result.htmlName}"
style="${jmeter.home}/extras/jmeter-results-detail-report_21.xsl">
<param name="dateReport" expression="${report.datestamp}"/>
</xslt>
<xslt
classpathref="xslt.classpath"
force="true"
in="${jmeter.result.jtlNamedetail}"
out="${jmeter.result.htmlNamedetail}"
style="${jmeter.home}/extras/jmeter-results-shanhe-me.xsl">
<param name="dateReport" expression="${report.datestamp}"/>
</xslt>

如果知道XML的一些语法,应该一下就能看明白,我们只是加了一个标签,然后把里面用到的属性值定义好。好吧,不懂XML语法也能看懂,哈哈。

PS:
使用jmeter-results-shanhe-me.xsl的一些前置操作
1、下载style文件:jmeter.results.shanhe.me.xsl
2、把下载的文件放到jmeter的extras目录下。
3、修改jmeter.properties文件如下部分,我这里都修改成true,这样执行完脚本后就会保存这些结果到.jtl文件里面,重启jmeter生效:

jmeter.save.saveservice.data_type=true
jmeter.save.saveservice.label=true
jmeter.save.saveservice.response_code=true
# response_data is not currently supported for CSV output
jmeter.save.saveservice.response_data=true
# Save ResponseData for failed samples
jmeter.save.saveservice.response_data.on_error=false
jmeter.save.saveservice.response_message=true
jmeter.save.saveservice.successful=true
jmeter.save.saveservice.thread_name=true
jmeter.save.saveservice.time=true
jmeter.save.saveservice.subresults=true
jmeter.save.saveservice.assertions=true
jmeter.save.saveservice.latency=true
jmeter.save.saveservice.connect_time=true
jmeter.save.saveservice.samplerData=true
jmeter.save.saveservice.responseHeaders=true
jmeter.save.saveservice.requestHeaders=true
jmeter.save.saveservice.encoding=false
jmeter.save.saveservice.bytes=true
jmeter.save.saveservice.url=true
jmeter.save.saveservice.filename=true
jmeter.save.saveservice.hostname=true
jmeter.save.saveservice.thread_counts=true
jmeter.save.saveservice.sample_count=true
jmeter.save.saveservice.idle_time=true

3.XSL文件的定制

其实XSL语法跟XML挺像的,多看看我们可以进行定制,如定义接口排序,扩展性能指标,那样我们性能测试也能利用这个生成报告,响应时间超过3秒的接口标黄显示,直观显示接口响应的性能状态,主要还是看公司的业务需求。

我会把扩展后的XSL也放到git地址,有需要的可以参考。

4.与Jenkins的集成

我们会用到两个插件,可到Jenkins的系统管理-》管理插件-》可选插件中搜索安装

4.1 HTML Publisher plugin

安装好HTML Publisher plugin之后,会在新建或者编辑项目时,在【增加构建后操作步骤】出现【Publish HTML reports】的选项

这样我们就可以在Jenkins中进行接口自动化测试报告的查看

4.2 Performance plugin

安装好Performance plugin之后,会在新建或者编辑项目时,在【增加构建后操作步骤】出现【Publish Performance test result report】的选项


仔细的朋友可以发现,我们使用HTML Publisher plugin用到了html文件,并且目录是指定的,难道每次每次生成的接口测试结果都要被覆盖?不存在的,当一个接口变动时,可通过接口历史响应,判断接口性能变化。使用HTML Publisher plugin用到了jtl文件名字是指定的,难道也要覆盖?也不存在的,这里放一下我的解决方案。

timestamp=`date +%Y%m%d%H%M%S`
pwd
rm -f ./*.html
mkdir /jmeter/report/$timestamp
cp /jmeter/report/*.jtl /jmeter/report/$timestamp/
cp /jmeter/report/*.html /jmeter/report/$timestamp/

cp /jmeter/report/R*.html ./
rm -f /jmeter/report/latest/*.jtl
rm -f /jmeter/report/latest/*.html
cp /jmeter/report/*.jtl /jmeter/report/latest/
cd /jmeter/report/latest
mv -f *.jtl latest.jtl
rm -f /jmeter/report/*.jtl
mv -f /jmeter/report/*.html /jmeter/report/latest

思路:每次生成的两个html文件和jtl文件都放到类似20170831102019(时间戳)的目录下,保证每次的接口测试结果都能保存。
结果保存了,但是每次的jtl文件名字是不一样的,就算把jtl文件名字改成一致的,目录也是不同的,于是我们新建了一个latest目录,每次执行接口测试都保证latest目录的html和jtl文件是最新的,并且把jtl文件的名字改成latest.jtl,完美达到我们的要求。只要思想不滑坡,办法总比困难多😋

4.3 Jenkins不显示html的CSS样式

说到这里,会有一个问题,就是Jenkins默认不显示html的CSS样式,所以界面很丑,如图:


网上一致的解决方法:jenkins->系统管理->脚本命令行,执行命令:

System.setProperty("hudson.model.DirectoryBrowserSupport.CSP","sandbox allow-scripts; default-src 'none';script-src 'unsafe-inline' http://code.jquery.com/jquery-2.1.0.min.js; img-src dohko.hpeswlab.net 'self' data: ; style-src 'unsafe-inline' 'self';");
System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")

重新运行下job生成html,就会正常显示。

但是,每次重启Jenkins,都需要再运行一次,咋搞,不太智能。
我们理解一下网上解决方法的原理,就是执行一段Groovy script,并且要在JOB开始前执行,然后我们知道有个Groovy plugin,可以执行Groovy脚本,那么,我们,就。。。搞起来

html报告显示正常的结果:

4.4 jenkins配置自动发送邮件

1.开通163的SMTP服务,需要发一条短信,163会给让你设置一个密码(不是你的163邮箱密码哦)
2.安装 Email Extension Plugin 插件
3.进入系统管理--系统设置
注意自带邮箱插件->邮件通知 对应插件E-mail Notification的配置
扩展插件->Extended E-mail Notification对应插件Editable Email Notification的配置
系统设置中邮件通知和Extended E-mail Notification(配置项多一些)的配置基本一致


JOB页面使用Extended E-mail Notification插件的配置图:

按需整理好后会把用到的build.xml,扩展的xsl和Jenkins中JOB的config.xml放到git地址
https://github.com/grizz/jmeter-master

欢迎交流指正,感谢阅读。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 18 条回复 时间 点赞
grizz Jmeter 接口自动化-脚本数据分离实例 中提及了此贴 09 May 12:34

楼主去看看生成的jtl文件,使用jmeter聚合报告查看下,是不是和你的xsl定制生成的HTML报告数据不一样,这个xsl文件网上计算的逻辑是有问题的;你这个我已经实现了,就是没写过文档,唯一我发现有问题的地方就是xsl逻辑有问题,你自己看吧

grizz #3 · May 10, 2018 作者

首先感谢仔细阅读

jtl文件在jmeter的聚合报告中打开,跟我的报告对比图如下:

看得出QPS的值跟jmeter的是一致的,其中90%Line我的为22ms,jmeter为94ms,95%Line都为94ms
这里面一个12个接口,响应时间从小到大最后3个是22ms,94ms,192ms(这个从报告看得出,因为是按照时间倒序排的)
计算90%line是用12*90%=10.8,我是向下取整得到10,所以取的是22ms。
计算95%line是用12*95%=11.4,我是向下取整得到11,所以取的是94ms。
但jmeter都是94ms,可能是对10.8和11.4四舍五入,都得到11,所以取的都是94ms。

我的关键逻辑是这样的,根据网上的修改后的:
当只有一个数据,向上取整,当有多个数据时向下取整,报告会好看一点,但数据量大的时候,跟jmeter应该无差别,或者用round函数对数据四舍五入也可以,问题是自己知道怎么算的就好。

<!-- -95% line time -->
<xsl:template name="lineTime95">
<xsl:param name="nodes" select="/.." />
<xsl:choose>
<xsl:when test="not($nodes)">NaN</xsl:when>
<xsl:otherwise>
<xsl:for-each select="$nodes">
<xsl:sort data-type="number" />
<!-- last() 返回当前上下文中的最后一个节点位置数 -->
<!-- ceiling(number) 返回大于number的最小整数 -->
<!-- floor(number) 返回不大于number的最大整数 -->
<xsl:choose>
<!-- 当只有一个节点时,向上取整 -->
<xsl:when test="last() = 1">
<xsl:if test="position() = ceiling(last()*0.95)">
<xsl:value-of select="number(.)" />
</xsl:if>
</xsl:when>
<xsl:otherwise>
<!-- 当有多个节点时,向下取整 -->
<xsl:if test="position() = floor(last()*0.95)">
<xsl:value-of select="number(.)" />
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

网上的模板前面数据都没有错,只是QPS这项最重要的算错了,我也看了你的【21.xsl】,QPS的算法是错的,你把取样取数设置为2,试试就知道了;QPS=当前样本的请求总数/(当前样本的第一个请求的结束时间-当前样本最后一个请求的结束时间+最后一个请求的响应时间),你截图中的全局QPS就是错的,你把取样数设置多一些,再试试看

grizz #5 · May 11, 2018 作者
阿宽 回复

单个是没错的,总体的我就是把单个相加除以个数,所以得到27.842/s,但是jmeter的值6.7/s差别真的有点大,肯定不是取的平均值吧,因为没有几个比6.7/s小的,我是按照自己的理解算的,你是怎么理解jmeter中Throughout这个值的

可以看下官方文档:http://jmeter.apache.org/usermanual/glossary.html#Throughput

另外我把我的理解说下:
Throughput = (number of requests) / (total time)
total time = 测试结束时间 - 测试开始时间
测试结束时间 = 最后一个请求的开始时间 + 最后一个请求响应时间 #最后一个请求开始时间=max(当前样本的最大时间戳)
测试开始时间 = 第一个请求的开始时间 #第一个请求开始时间=min(当前样本的最小时间戳)
也即QPS=当前样本的请求总数/(当前样本最后一个请求的开始时间+最后一个请求的响应时间-当前样本的第一个请求的开始时间)
而你的xsl中,忽略了响应时间。
这个公式中,如果最后一个请求响应时间较短,则近乎等于按你的公式来算,影响较小;如果响应时间比较大,则和jmeter数据差距就比较大了。验证这个结果,你可以试试用公网IP,这样响应时间就比较长了,试试是不是这样的。

这个公式适用于计算单个用例组和全局的QPS。

大神,我有个问题,比如你resource 目录下有a,b,c三个jmeter 工程,你想过怎么控制哪个要执行哪个先执行?还有就是如果你在jmeter中使用mysql进行参数化,你的jdbc的jar路径是绝对路径,当你把jmeter和jenkins 结合,这jdbc的路径就又需要修改。还有就是在jenkins 中用命令行执行三个工程,内存消耗大。越来越觉得,jmter不适合和jenkins 整合

grizz #8 · May 16, 2018 作者
bill 回复

1·resource 目录下有a,b,c三个jmeter 工程,你想过怎么控制哪个要执行哪个先执行
由Ant所在目录lib子目录下ant-jmeter-1.1.1.jar的"org.programmerplanet.ant.taskdefs.jmeter.JMeterTask"这个类控制

你也可以从ant的 运行日志中查看a,b,c的执行顺序,优先级应该是a>b>c,想自己控制可以改jar包代码
2·在jmeter中使用mysql进行参数化,你的jdbc的jar路径是绝对路径
可以在你本机jmeter和jenkins使用的jmeter中分别将jdbc的jar包路径设置成全局变量在jmeter.properties中,取的话都用${mysqlJar}
如本机jmeter的jmeter.properties新增行mysqlJar=D:/benji/mysql.jar,jenkins使用的jmeter的jmeter.properties新增行mysqlJar=D:/jenkins/mysql.jar
3·jenkins 中用命令行执行三个工程,内存消耗大
jmeter的PerfMon Metrics Collector插件可以监控jmeter运行时本机的CPU内存等性能指标,内存消耗大可以考虑用jenkins远程运行jmeter脚本,别用搭建jenkins的机器运行

看了一下楼主的git目录,jmeter-results-detail-report_21.xsl这个样式文件还是旧的呢,能不能给个新的参考一下,感谢

大神求回复,邮件自动发送后报错:ERROR: File './${mail_content}' does not exist
百思不得其解……

另外,下面这个代码怎么实现啊?放在哪里实现?

timestamp=date +%Y%m%d%H%M%S
pwd
rm -f ./.html
mkdir /jmeter/report/$timestamp
cp /jmeter/report/
.jtl /jmeter/report/$timestamp/
cp /jmeter/report/*.html /jmeter/report/$timestamp/

cp /jmeter/report/R*.html ./
rm -f /jmeter/report/latest/.jtl
rm -f /jmeter/report/latest/
.html
cp /jmeter/report/.jtl /jmeter/report/latest/
cd /jmeter/report/latest
mv -f *.jtl latest.jtl
rm -f /jmeter/report/
.jtl
mv -f /jmeter/report/*.html /jmeter/report/latest

grizz #12 · December 12, 2018 作者
drppsy 回复

增加构建步骤中选择执行shell
填入这段shell命令,可能要根据你的目录进行相应修改

grizz #13 · December 12, 2018 作者
drppsy 回复

Editable Email Notification中的配置

${FILE,path="./${mail_content}"}这段的作用是把HTML报告当成邮件正文发送,mail_content就是HTML报告的文件名,我定义了全局变量所以能取到,你取不到的话应该是没有定义,所以报错找不到那个文件

大神,问下,加了插件,但是Performance Trend 里没有曲线显示是怎么回事呢?

楼主,我想问下。jmeter脚本有错误时,Jenkins运行时不会进行提醒。需要查看测试报告才能发现错误。要怎么样才能比较直观的发现脚本运行错误呢

grizz #16 · February 14, 2019 作者
Emulator 回复

运行成功了很多次都没有曲线显示吗

grizz 回复

是的,

控制台出现这样的,

是不是这里的配置不对

grizz #18 · February 19, 2019 作者
Emulator 回复

Publish Performance test result report插件只有Source data files (autodetects format):需要配置,其他默认就好了
Jenkins日志如下:

可能是你的jtl有问题,jenkins插件解析不了jtl,你可以尝试在jmeter里面打开jtl试试:

写的不错,收藏一下!

grizz 请教一个 Jenkins 发送邮件带附件的问题 中提及了此贴 22 Apr 15:36
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up