? ? 依照市面上目前自動化的測試工具和產(chǎn)品腔丧,我們發(fā)現(xiàn)它們對常規(guī)協(xié)議:http惩阶、https等協(xié)議支持較好辐赞,可是對于非常規(guī)協(xié)議,如:dubbo搂根、rmp等協(xié)議或者公司內(nèi)部協(xié)議的支持不太好珍促,基本上是完全不支持的。我們在本文來探討一下如何支持非常規(guī)協(xié)議的自動化測試剩愧。
? ?很多人會想到將非常規(guī)協(xié)議轉(zhuǎn)變?yōu)槌R?guī)協(xié)議后再做壓測猪叙,這種方法的適用性不高,我們來舉個例子:
? ?我們想對某個dubbo協(xié)議的服務(wù)進(jìn)行壓測仁卷,dubbo協(xié)議的另一側(cè)是企業(yè)的總線接入服務(wù)穴翩。這種場景下我們?nèi)绻麑ubbo協(xié)議包裝一層成為http協(xié)議,那么http服務(wù)器有可能成為壓測的瓶頸锦积,因?yàn)槠髽I(yè)總線的性能是很強(qiáng)勁的芒帕,因此需要使用復(fù)雜的http服務(wù)集群才能擺脫http服務(wù)器的瓶頸。小編就被這種方案害苦過丰介,曾有一次壓測集團(tuán)的總線服務(wù)背蟆,因?yàn)楝F(xiàn)成的工具不支持dubbo協(xié)議,故將dubbo協(xié)議轉(zhuǎn)換成http協(xié)議使用jmeter集群進(jìn)行壓測哮幢,發(fā)現(xiàn)性能普遍較低淆储,和預(yù)想的性能有十倍之差,而問題還不只出現(xiàn)在http服務(wù)器家浇,而是出在http調(diào)用dubbo時服務(wù)器對連接的承載數(shù)目,這種協(xié)議轉(zhuǎn)換的方案慎用碴裙。
? ?那么我們要使用哪種方法去進(jìn)行這些非常規(guī)協(xié)議的自動化測試呢钢悲?
? ?jmeter提供了一種java調(diào)用,可以直接調(diào)用java的類舔株,如果我們將要封裝的協(xié)議放在java類中莺琳,直接調(diào)用java類的話,其開銷并不大载慈,其一是因?yàn)閖ava類的運(yùn)行在壓測機(jī)惭等,使用壓測機(jī)集群可以幾乎無限制的消滅掉這種瓶頸,其二是java類的系統(tǒng)開銷較低办铡,幾乎不會對壓測造成影響辞做。下面我們將對其實(shí)現(xiàn)方式進(jìn)行詳細(xì)的介紹。
我們將首先介紹通用的方法:
一.啟動JMeter
下載:
http://jmeter.apache.org/download_jmeter.cgi
啟動:
Linux環(huán)境下運(yùn)行 $安裝目錄/bin/jmeter.sh
Windows下運(yùn)行 $安裝目錄/bin/jmeter.bat
二.編寫用例
針對"Java請求"類型的測試寡具,需要基于JMeter測試框架編寫用例秤茅。
1、新建一個普通的Java工程童叠;
2框喳、將 $JMeter安裝目錄/lib/ 目錄引入工程;
3、新建Java Class五垮,如下的"PerformanceTest "乍惊,并繼承"AbstractJavaSamplerClient";
代碼示例:
Java代碼
/**
*
*/
packagetest;
importorg.apache.jmeter.config.Arguments;
importorg.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
importorg.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
importorg.apache.jmeter.samplers.SampleResult;
/**
*?@author dingjingjing
*
*/
publicclassPerformanceTestextendsAbstractJavaSamplerClient?{
/**
*
*/
privatestaticlongstart?=0;
privatestaticlongend?=0;
/**
*?執(zhí)行runTest()方法前會調(diào)用此方法,可放一些初始化代碼
*/
publicvoidsetupTest(JavaSamplerContext?arg0)?{
//?開始時間
start?=?System.currentTimeMillis();
}
/**
*?執(zhí)行runTest()方法后會調(diào)用此方法.
*/
publicvoidteardownTest(JavaSamplerContext?arg0)?{
//?結(jié)束時間
end?=?System.currentTimeMillis();
//?總體耗時
System.err.println("cost?time:"+?(end?-?start)?/1000);
}
/**
*?JMeter界面中可手工輸入?yún)?shù),代碼里面通過此方法獲取
*/
publicArguments?getDefaultParameters()?{
Arguments?args?=newArguments();
returnargs;
}
/**
*?JMeter測試用例入口
*/
@Override
publicSampleResult?runTest(JavaSamplerContext?arg0)?{
SampleResult?sr?=newSampleResult();
try{
//?Start
sr.sampleStart();
/**
*?Start~End內(nèi)的代碼會被JMeter
*?納入計(jì)算吞吐量的范圍內(nèi),為了使
*?性能結(jié)果合理,無關(guān)代碼不必放此
*/
//?TODO
/**
*?True/False可按測試邏輯傳值
*?JMeter會對失敗次數(shù)做出統(tǒng)計(jì)
*/
sr.setSuccessful(true);
//?End
sr.sampleEnd();
}catch(Exception?e)?{
e.printStackTrace();
}
returnsr;
}
}
4放仗、導(dǎo)出成Jar并置于 $JMeter安裝目錄/lib/ext/ 下润绎,若有依賴Jar也置于 $JMeter安裝目錄/lib/ 下;
5匙监、啟動或重啟JMeter凡橱。
三、運(yùn)行用例
1亭姥、主界面左側(cè)“測試計(jì)劃”稼钩,右鍵菜單->添加->Threads(Users)->線程組;
2达罗、再選中剛才新增的"線程組"坝撑,右鍵菜單->添加->Sampler->Java請求;
3粮揉、再選中剛才新增的"Java請求"巡李,右鍵菜單->添加->監(jiān)視器->聚合報告;
4扶认、選擇想測試的類名侨拦,并在"線程組"選項(xiàng)中輸入循環(huán)次數(shù)及并發(fā)線程數(shù);
5辐宾、點(diǎn)擊菜單欄上"運(yùn)行"->啟動后便開始運(yùn)行狱从,在"聚合報告"查看結(jié)果數(shù)據(jù)。
Tips:
1.若在"Java請求"選項(xiàng)中未找到測試用例類名: 則請先確認(rèn)用例是否繼承了JMeter框架的基類叠纹; 其次保證用例Jar文件在 $安裝目錄/lib/ext/ 下季研; 嘗試重啟JMeter。
2.如果對于java請求的讀取仍然存在各種各樣的問題誉察,很大可能是java版本不一致造成的与涡,jmeter編譯時java版本大多為1.6,所以可以嘗試將編譯java類java版本保持和jmeter編譯java版本的一致持偏,或者拿到j(luò)meter源碼驼卖,在本地再次編譯jmeter。
在這里貼上jmeter調(diào)用dubbo協(xié)議的代碼:
package com.pingan;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import org.apache.jmeter.config.Arguments;
importorg.apache.jmeter.protocol.java.sampler.JavaSamplerClient;
importorg.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
importorg.apache.jmeter.samplers.SampleResult;
importcom.alibaba.dubbo.config.ApplicationConfig;
importcom.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
importcom.alibaba.dubbo.rpc.service.GenericService;
import com.paic.pafa.ac.dubbo.GenericParam;
importcom.paic.pafa.ac.dubbo.GenericResult;
public class DubboClient implementsJavaSamplerClient {
publicstatic int j = 0;
publicstatic int j1 = 0;
publicstatic int p= 0;
GenericServicegenericService = null;
//publicDubboClient() {
//System.out.println("gouzao");
//run();
//System.out.println("finish");
//
//}
publicSampleResult runTest(JavaSamplerContext jsc) {
SampleResultsampleResult = new SampleResult();
GenericParamparam = new GenericParam();
param.setParams(getParams());
try{
sampleResult.sampleStart();
GenericResultresult = (GenericResult) genericService.$invoke("anymethod",
newString[] { "com.paic.pafa.ac.dubbo.GenericParam" }, new Object[] {param });
System.out.println(result.getResult());
sampleResult.setResponseCodeOK();
sampleResult.setResponseMessageOK();
sampleResult.setSuccessful(true);
sampleResult.setResponseData(result.getResult().toString(),"UTF-8");}
catch(Exceptione){
sampleResult.setResponseCode("error");
sampleResult.setResponseMessage("error");
sampleResult.setSuccessful(false);
sampleResult.setResponseData("帥哥鸿秆,貌似是你的網(wǎng)不通款慨,或者服務(wù)掛了", "UTF-8");
j1++;
}
finally{
sampleResult.sampleEnd();
}
returnsampleResult;
}
publicstatic void main(String[] args) {
DubboClientclient = new DubboClient();
client.setupTest(null);
client.runTest(null);
}
publicString run() {
//DubboClientclient = new DubboClient();
setupTest(null);
returnrunTest(null).toString();
}
publicstatic void main1(String[] args) {
intcount=90;
inti=0;
for(;i
newThread(new Runnable() {
publicvoid run() { //新啟動一個線程,避免時間的浪費(fèi)
for(;;){
DubboClientclient = new DubboClient();
client.setupTest(null);
client.runTest(null);
client.j++;
System.out.println(j+"error"+j1);
}
}
}).start();}
}
publicArguments getDefaultParameters() {
//TODO Auto-generated method stub
returnnull;
}
publicvoid setupTest(JavaSamplerContext arg0) {
try{
ReferenceConfigreference = new ReferenceConfig();
reference.setUrl("dubbo://10.21.99.79:20882/esb-proxy.service.B10013_000000");
reference.setInterface("esb-proxy.service.B10013_000000");
reference.setGeneric(true);
reference.setApplication(newApplicationConfig("ff-test"));
reference.setTimeout(10000);
reference.setRegistry(newRegistryConfig("zookeeper://10.21.66.48:2181"));
genericService = reference.get();}
catch(Exceptione){
System.out.print("error\n\n\n");
}
}
publicvoid teardownTest(JavaSamplerContext arg0) {
//TODO Auto-generated method stub
}
publicMap getParams() {
Map params = new HashMap();
Map esbRequest = new HashMap();
Map header = new HashMap();
Map content = new HashMap();
esbRequest.put("content",content);
esbRequest.put("header",header);
StringsendSerialNo = this.getSeqNo();
esbRequest.put("sendSerialNo",sendSerialNo);
esbRequest.put("idType","1");
esbRequest.put("idNo","1");
params.put("esbRequest",esbRequest);
params.put("timeOutMs","30000");
params.put("systemId","958537");
params.put("requestNo",sendSerialNo);
returnparams;
}
publicString getSeqNo() {
returnString.valueOf(System.currentTimeMillis() + System.nanoTime() + newRandom().nextInt(2));
}