轉自:http://www.cnblogs.com/victorcai0922/archive/2012/06/20/2555502.htmlhtml
最近在利用Jmeter來作一套自動化性能測試框架,作自動化性能測試框架的目的 是但願可以針對系統作一個benchmark的性能測試,可以快速的在每一個版本發佈後,對該版本進行benchmark性能測試,以比較與上一個版本的性 能是否發生變化,若發生變化即可以快速的通知開發人員以肯定性能發生變化的模塊或者代碼。同時測試或者開發能夠上傳性能測試腳本到測試平臺,測試平臺接到 測試腳本後就能夠進行性能測試並返回測試結果.基於這一點的考慮是,通常的測試工程師(特別想功能測試工程師)和開發工程師可能沒有相關的性能測試環境供 他們使用,所以創建這樣的平臺就是但願可以讓每一個人都能快速的進行性能測試,而不須要關注性能測試環境(每每配置一個性能環境可能須要很長的時候).git
1.框架簡要介紹github
選擇Jmeter來搭建這樣一個平臺是基於Jmeter自己的Open source, 而且是用純JAVA開發的測試工具,方便與其餘的工具的集成和擴展。最重要的是,你能夠看到源碼。web
這套框架基本的執行流程和邏輯其實很簡單,利用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插件在這裏不具體講,能夠參考網上資料)中的主要調用代碼:app
重點參考TestManager這個類,這個類是主要用來啓動Jmeter的,咱們能夠參考這個類中的executeSingleTest(File test)這個方法:框架
這個方法驗證了咱們剛纔這個猜測。在完成經過MAVEN啓動Jmeter的分析事後,咱們所要作的事情就是如何解析Jmeter運行後所獲得的測試結果,並將這個測試結果以相關的格式展示出來。webapp
關於如何具體解析Jmeter執行結果將在下篇Blog中具體闡述。
繼上篇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中繼續闡述。
繼上篇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有一個缺陷,個人工程中有修復的代碼。