转自:http://www.cnblogs.com/victorcai0922/archive/2012/06/20/2555502.html
Jmeter+maven+Jenkins构建云性能测试平台(一)
最近在利用Jmeter来做一套自动化性能测试框架,做自动化性能测试框架的目的 是希望能够针对系统做一个benchmark的性能测试,能够快速的在每个版本发布后,对该版本进行benchmark性能测试,以比较与上一个版本的性 能是否发生变化,若发生变化便可以快速的通知开发人员以确定性能发生变化的模块或者代码。同时测试或者开发可以上传性能测试脚本到测试平台,测试平台接到 测试脚本后就可以进行性能测试并返回测试结果.基于这一点的考虑是,一般的测试工程师(特别想功能测试工程师)和开发工程师可能没有相关的性能测试环境供 他们使用,因此建立这样的平台就是希望能够让每个人都能快速的进行性能测试,而不需要关注性能测试环境(往往配置一个性能环境可能需要很长的时候).
1.框架简要介绍
选择Jmeter来搭建这样一个平台是基于Jmeter本身的Open source, 并且是用纯JAVA开发的测试工具,方便与其他的工具的集成和扩展。最重要的是,你可以看到源码。
这套框架基本的执行流程和逻辑其实很简单,利用Jenkins的CI功能,实时检查脚本库,若有变更便调用JMeter来执行脚本,并将测试结果通过邮件或其他方式通知相关人员。主要逻辑图如下所示:
2. Maven执行Jmeter
MAVEN是一个非常优秀的项目管理工具,关于Maven和Ant的主要区别可以去网上查询,我们在这里主要介绍一下用MAVEN如何去运行 JMeter, JMeter支持多种运行方式,有GUI方式和NONGUI方式,各有优势,我们在自动化性能测试平台的搭建中采用NonGUI方式来运行测试脚 本,NonGuI方式其实也就是通过Command命令来运行,那么如何通过Maven来调用呢,不用慌张,已经有Jmeter-maven- plugin这样一个Maven插件来运行Jmeter了,如果看过Jmeter源码的话,可以看到在Jmeter中有这样一个Class,叫做 NewDriver.class,这个类是Jmeter的入口,我们可以看一下这个类的Main方法:
看到try模块中的最后几行可以看到,通过Java反射机制,JMeter.start()方法被调用到,并且将相关的参数传递给该方法。因此我们 可以想象到JMeter-maven插件中肯定也是通过调用这个方法来启动JMeter的,我们来看一下JMeter-maven-plugin这个插件 (关于如何开发maven插件在这里不具体讲,可以参考网上资料)中的主要调用代码:
重点参考TestManager这个类,这个类是主要用来启动Jmeter的,我们可以参考这个类中的executeSingleTest(File test)这个方法:
这个方法验证了我们刚才这个猜想。在完成通过MAVEN启动Jmeter的分析过后,我们所要做的事情就是如何解析Jmeter运行后所得到的测试结果,并将这个测试结果以相关的格式展现出来。
关于如何具体解析Jmeter执行结果将在下篇Blog中具体阐述。
Jmeter+maven+Jenkins构建云性能测试平台(二)
继上篇Blog,本篇将重点介绍利用Maven并开发插件解析Jmeter生成的 报告,于是就有Jmeter-analysis-maven-plugin这个插件,这个插件是由Aren Franka开发的,但是当你使用这个插件的时候会发现,它只能解析Http request请求的报告,不能解析如Webservice request请求的报告以及其他请求的报告,这是由于这个插件的代码中存在一个bug,于是自己动手修改了这个bug,因为通过Nongui生成的 Jmeter报告是以.jtl结尾的类似于xml的文件,因此在Jmeter-analysis-maven-plugin这个插件中会采用SAX来解析 报告文件。具体来看一下Jmeter报告文件的格式:
<?xml version="1.0" encoding="UTF-8"?> <testResults version="1.2"> <sample t="49" lt="0" ts="1339404299860" s="true" lb="PoscPaymentServiceImplService" rc="200" rm="OK" tn="posc 1-1" dt="text" by="713"/> <sample t="45" lt="0" ts="1339404301064" s="true" lb="PoscPaymentServiceImplService" rc="200" rm="OK" tn="posc 1-13" dt="text" by="713"/> <sample t="45" lt="0" ts="1339404301166" s="true" lb="PoscPaymentServiceImplService" rc="200" rm="OK" tn="posc 1-14" dt="text" by="713"/> <sample t="53" lt="0" ts="1339404301266" s="true" lb="PoscPaymentServiceImplService" rc="200" rm="OK" tn="posc 1-15" dt="text" by="713"/> <sample t="49" lt="0" ts="1339404301362" s="true" lb="PoscPaymentServiceImplService" rc="200" rm="OK" tn="posc 1-16" dt="text" by="713"/> <sample t="129" lt="0" ts="1339404301465" s="true" lb="PoscPaymentServiceImplService" rc="200" rm="OK" tn="posc 1-17" dt="text" by="713"/> <sample t="51" lt="0" ts="1339404301564" s="true" lb="PoscPaymentServiceImplService" rc="200" rm="OK" tn="posc 1-18" dt="text" by="713"/> <sample t="55" lt="0" ts="1339404301665" s="true" lb="PoscPaymentServiceImplService" rc="200" rm="OK" tn="posc 1-19" dt="text" by="713"/> <sample t="53" lt="0" ts="1339404301764" s="true" lb="PoscPaymentServiceImplService" rc="200" rm="OK" tn="posc 1-20" dt="text" by="713"/> </testResults>
这是一个webservice请求所得到的测试结果,所以每个请求都是以sample开始的,如果是http请求的话,会以httpsample开 始,大家可以在我的代码中看到我用了一个hashset将这两种element都放在里面,然后通过判断是否存在相关的element来解析报告,原代码 中只考虑了http这种情况,不过我已经email给aren,他已经修复了这个bug。下面我们具体看一下每个属性的含义,其中ts表示每个样本结束的 Timestamp,s表示请求的状态,成功为true,失败为false,lb表示请求的名称,rc表示请求的response code, rm表示response message,tn表示thread name,dt表示data type, dy表示data byte。通过解析这个xml文本我们可以生成这样一个请求结果:
通过解析可以得到response time, tps等,还可以生成图表如下所示:
这个可以看到是请求的表现图。
Aren在开发Jmeter-analysis-maven-plugin这个插件的时候已经提供了,生成html,cvs, chart几种方式,我在代码中增加了一种方式就是将测试结果存入数据库。
具体大家可以看我后续在github上上传的代码。Aren在开发该插件的时候没有将Tps, VUser这些数据放在报告中,我也在代码中做了一些修改来展示这些数据。
总而言之使用这个插件可以很方便的来进行性能测试,我们只需要将上一篇blog所提到的关于Jmeter-maven-plugin结合本篇文章所 提到的Jmeter-analysis-maven-plugin结合起来使用便可以方便的构建各种测试场景,我们只需要在pom.xml中进行如下配 置:
<plugin> <groupId>${project.groupId}</groupId> <artifactId>jmeter-maven-plugin</artifactId> <version>${project.version}</version> <!-- configure different executions of the plugin --> <executions> <execution> <!-- 1) first test run warms up the webserver. Used to fill caches. With a different set of properties since it runs much shorter than a normal test and also the rate of requests/second may be much lower. Maybe also use a different URL set. --> <id>warmup</id> <phase>integration-test</phase> <goals> <goal>jmeter</goal> </goals> <configuration> <propertiesUser> <!--Accesses urls for warmup (compiles JSPs, fills caches, ...)--> <threadgroup00.name>warmup</threadgroup00.name> <!--number of threads to use--> <threadgroup00.numberOfThreads>1</threadgroup00.numberOfThreads> <!--delay of the test in seconds--> <threadgroup00.scheduledDelay>0</threadgroup00.scheduledDelay> <!--duration of the test in seconds--> <threadgroup00.scheduledDuration>30</threadgroup00.scheduledDuration> <!--how long till all threads are up and running in seconds--> <threadgroup00.rampUp>1</threadgroup00.rampUp> <!--target throughput of all threads of the group per minute--> <!-- <threadgroup00.throughput>100000000</threadgroup00.throughput>--> <!-- use uris from given file --> <!-- <threadgroup00.dataFile>${webapp.uris}</threadgroup00.dataFile> --> </propertiesUser> </configuration> </execution> <execution> <!-- 2) Performance test --> <id>test</id> <phase>integration-test</phase> <goals> <goal>jmeter</goal> </goals> <configuration> <propertiesUser> <!--A user which accesses all URLs--> <threadgroup00.name>posc</threadgroup00.name> <!--number of threads to use--> <threadgroup00.numberOfThreads>30</threadgroup00.numberOfThreads> <!--number of loops--> <threadgroup00.numberOfLoops>2</threadgroup00.numberOfLoops> <!--delay of the test in seconds--> <threadgroup00.scheduledDelay>0</threadgroup00.scheduledDelay> <!--duration of the test in seconds--> <threadgroup00.scheduledDuration>30</threadgroup00.scheduledDuration> <!--how long till all threads are up and running in seconds--> <threadgroup00.rampUp>2</threadgroup00.rampUp> <!--target throughput of all threads of the group per minute--> <!-- <threadgroup00.throughput>100000000</threadgroup00.throughput>--> <!-- use uris from given file --> <!-- <threadgroup00.dataFile>${webapp.uris}</threadgroup00.dataFile>--> </propertiesUser> </configuration> </execution> </executions> <!-- general configuration for all executions --> <configuration> <!-- configure which testplans to use --> <testFilesIncluded> <testFilesIncluded>PoscPaymentServiceImplService.jmx</testFilesIncluded> </testFilesIncluded> <!-- protocol, server and port of tested webapp --> <propertiesUser> <protocol>${webapp.protocol}</protocol> <server>${webapp.host}</server> <port>${webapp.port}</port> </propertiesUser> </configuration> </plugin> <plugin> <groupId>${project.groupId}</groupId> <artifactId>jmeter-analysis-maven-plugin</artifactId> <version>${jmeter.analysis.maven.plugin.version}</version> <executions> <execution> <goals> <goal>analyze</goal> </goals> <phase>post-integration-test</phase> <configuration> <!-- source file that contains jmeter result data. Needs to be XML format or a GZIPed XML format --> <source>${project.build.directory}/jmeter/results/PoscPaymentServiceImplService-120613.jtl</source> <!-- directory where to store analysis report files. At least a file "summary.txt" will be stored here. --> <targetDirectory>${project.build.directory}/reports</targetDirectory> <!-- Defines groups of requests by URL patterns, e.g. URIs starting with /mock/page are associated with group "pages". All analysis results are If there is no such mapping then the threadgroups from the jmeter.xml are used. --> <!--<requestGroups>--> <!--<test>/en-US/firefox/**</test>--> <!--</requestGroups>--> <!-- If set to true, additional files "<category>-sizes.csv" and "<category>-durations.csv" will be stored. These files contain detailed information for response size and response durations for every URI. --> <generateCSVs>true</generateCSVs> <!-- If set to true, additional chart files "<category>-durations.png" will be created. --> <generateCharts>true</generateCharts> <!-- The database configuration --> <userName>xxx</userName> <passWord>xxx</passWord> <dataBase>xxx</dataBase> <host>xxx.xxx.xxx.xxx:3306</host> <!-- Mapping from resource URL to file name. Every resource will be downloaded and stored in ‘targetDirectory‘ with the given filename. Tokens "_FROM_" and "_TO_" can be used as placeholders. These placeholders will be replaced by timestamps of execution interval (formatted as ISO8601, e.g. ‘20111216T145509+0100‘). --> <!--<remoteResources>--> <!--<property>--> <!--<name>http://yourhost/path?from=_FROM_&to=_TO_</name>--> <!--<value>my_resource.txt</value>--> <!--</property>--> <!--</remoteResources>--> </configuration> </execution> </executions> </plugin>
便可以完成一个测试场景,关于具体每一个element,这里不做详细解释,因为在注解中已经写的很详细了。关于如何配合CI构建云测试平台将在下一篇blog中继续阐述。
Jmeter+maven+Jenkins构建云性能测试平台(三)
继上篇blog,本篇我们具体讨论一下,如何利用Jenkins做持续的性能测 试,前面我们说过因为互联网软件发布频繁,需要做到小步快跑,快速反馈,我们在自动化,接口测试的时候已经能够做到快速反馈,所以希望性能测试同样能够快 速反馈,我们希望的是能够构建一个云性能测试平台,这样能够让开发工程师,功能测试工程师都参与到性能测试中来,而不仅仅是由性能测试工程师在功能测试之 后再进行性能测试,总之快速反馈问题是互联网软件测试的宗旨。
下面具体谈一下我们是如何利用Jenkins来执行性能测试的,关于Jenkins的具体设置不再这里做介绍.
首先我们利用了git来做我们的脚本库,关于为什么选择git而不是subversion,大家可以去网上搜一下git和svn的区别。
其次持续性能测试有两个触发条件,第一个条件是当开发提交并发布新的版本的时候。第二个条件是性能测试脚本库脚本发生提交或者更新事件。
最后我们来配置我们的Jenkins build Job:
1.源码管理:
2.构建触发器:
3.构建后操作:
第三步解释一下,jenkins本身有一个Jmeter插件可以用来显示jmeter的一些执行结果.但是显示的结果有点粗糙.
以下这个图是我们自己解析后产生的结果:
从上面两个图中可以看到具体性能指标信息.
当然这里还没有包括服务器性能指标的收集,这个性能指标为的是快速的能够将一些基本的信息,如TPS,RESPONSE TIME,Standard devitation反馈给开发人员。
开发人员和测试人员可以将自己的测试脚本上传到脚本库里面,并在Jenkins里面配置好job,便可以利用Jenkins去调度和执行性能测试,并反馈测试报告。这个过程
类似云平台,解决了开发工程师和功能测试工程师没有具体的性能测试环境,也解决了性能测试及时性的问题,将性能测试前置到应用开发的各个阶段,而所需要的仅仅是
上传一个测试脚本,数据在云端已经帮你准备好。这就是所谓的云测试平台。
TPS这块的代码是作者自己加上去的,源码地址:https://github.com/victorcai0922/JmeterRunner
https://github.com/victorcai0922/JmeterAnalysis
这两个工程要配合适用因为是有pom互相依赖的,JemterAnalysis有一个缺陷,我的工程中有修复的代码。