因目前公司內部對http介面自動化,dubbo介面自動化都是使用指令碼來管理,技術棧還分java 和python ,內部對接很不方便,為了降低使用門檻,提升介面測試效率,所以決定在原有的功能用例管理平臺新增介面自動化來統一管理。
MeterSphere首先吹一波MeterSphere,個人覺得目前最好,功能最完善的介面自動化平臺,專案還在持續更新,並且有開源版,大家有興趣可以看一下專案程式碼https://github.com/metersphere/
個人對於這個平臺Http介面測試的部分理解:透過前端的入參將其封裝成JMeter能識別的 .jmx檔案,再透過JMeter的開放API去執行.jmx檔案。
這裡不得不說 該專案成員對JMeter非常熟悉,拋棄了jmeter難用的GUI,實現了一套非常好用UI,MeterSphere牛皮。
移植MeterSphere部分功能因為只需要介面測試的功能,所以只移介面測試部分。首先要做的就是在本地部署MeterSphere,官方文件只有docker部署教程,沒有windows下搭建的教程,而且sql檔案還分別放在不同的檔案下面,這無疑增加了二次開發 的成本。最後我在linux下部署專案,然後將sql匯出,在application.properties新增資料庫配置,註釋了原專案中的部分程式碼,在windows 下成功啟動,並且移植了介面測試模組的功能,然後,在測試的時候發現Dubbo介面無法成功呼叫,於是便有了第一次修改原始碼的操作……
發現問題:dubbo介面測試報錯MeterSphere這裡對Dubbo的配置很多,原本想簡化測試,這一套配置填下去,感覺比原有的方式還要麻煩,於是這裡我便將配置預設寫死,因為公司目前使用zk做註冊中心,其他的consumer&Service、Config Service這個配置也無需使用人員去配置。
在這裡插入圖片描述
但是當我填入對應的引數,請求dubbo介面的時候,問題就出現了
Failed to check the status of the service xxx.xxx.xxx . No provider available for the service
一直報錯找不到對應的服務,而我用現有的指令碼請求是能夠成功的,確認了環境沒有問題之後,我想可能是Dubbo版本的原因
定位問題:dubbo版本先來看兩張圖
在這裡插入圖片描述
在這裡插入圖片描述
我在maven倉庫裡面搜出來結果可以發現,Dubbo是在2.7.x版本被apache收錄,2.6.x的版本 groupId是com.alibaba。於是在專案中找到對應依賴,果然版本對不上,我們系統目前使用的Dubbo是2.5.x,阿里的版本。而這兩個版本連線ZK的方式也不同,老版本是透過
<dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> </dependency>
新版本則是使用
<dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> </dependency>
確定問題就是版本問,於是便開始了改原始碼
解決問題:修改jmeter-plugins-for-apache-dubbo外掛程式碼Jmeter支援Dubbo介面需要jmeter-plugins-for-apache-dubbo這個三方外掛支援,官方目前使用的是2.7.12不適合我們系統
<dependency> <groupId>io.metersphere</groupId> <artifactId>jmeter-plugins-dubbo</artifactId> <version>2.7.12</version> </dependency>
於是我將其修改為官方提供的1.3.x,發現呼叫Dubbo介面還是失敗,無法找到對應的服務。
最後我將1.3.x三方包下載到本地,研究其泛化呼叫的程式碼,發現其中很大一部分程式碼其實是對不同註冊中心如:zookeeper、nacos、redis的支援,而公司目前使用的zookeeper,我完全可以將這些不用的程式碼註釋掉,自己封裝一套泛化呼叫的邏輯,
@SuppressWarnings({"unchecked", "rawtypes"}) private Object callDubbo(SampleResult res) { try { ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>(); ApplicationConfig applicationConfig = new ApplicationConfig(); applicationConfig.setName("remoteInvoke"); applicationConfig.setVersion(""); RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setFile("/tmp/dubbo.cachr"); String address = getAddress(); registryConfig.setAddress(address); registryConfig.setProtocol("zookeeper"); reference.setApplication(applicationConfig); reference.setRegistry(registryConfig); // 弱型別介面名 String interfaceName = getInterface(); reference.setInterface(interfaceName); reference.setVersion("1.0.0"); // 宣告為泛化介面 reference.setGeneric(true); reference.setProtocol("dubbo"); //不重試,重試會造成資料重複執行 reference.setRetries(0); reference.setTimeout(10000); String methodName = getMethod(); if (StringUtils.isBlank(methodName)) { res.setSuccessful(false); return ErrorCode.MISS_METHOD.getMessage(); } // 用org.apache.dubboinfo.rpc.service.GenericService可以替代所有介面引用 GenericService genericService = reference.get(); if (genericService == null) { res.setSuccessful(false); return MessageFormat.format(ErrorCode.GENERIC_SERVICE_IS_NULL.getMessage(), interfaceName); } String[] parameterTypes = null; Object[] parameterValues = null; List<MethodArgument> args = getMethodArgs(); List<String> paramterTypeList = new ArrayList<String>();; List<Object> parameterValuesList = new ArrayList<Object>();; for(MethodArgument arg : args) { ClassUtils.parseParameter(paramterTypeList, parameterValuesList, arg); } parameterTypes = paramterTypeList.toArray(new String[paramterTypeList.size()]); parameterValues = parameterValuesList.toArray(new Object[parameterValuesList.size()]); Object result = null; try { result = genericService.$invoke(methodName, parameterTypes, parameterValues); res.setSuccessful(true); } catch (Exception e) { log.error("RpcException:", e); //TODO //當介面返回異常時,sample標識為successful,透過響應內容做斷言來判斷是否標識sample錯誤,因為sample的錯誤會統計到用例的error百分比內。 //比如介面有一些校驗性質的異常,不代表這個操作是錯誤的,這樣就可以靈活的判斷,不至於正常的校驗返回導致測試用例error百分比的不真實 res.setSuccessful(true); result = e; } return result; } catch (Exception e) { log.error("UnknownException:", e); res.setSuccessful(false); return e; } finally { //TODO 不能在sample結束時destroy// if (registry != null) {// registry.destroyAll();// }// reference.destroy(); } }
最後,將程式碼打成jar包,透過maven離線呼叫
<dependency> <groupId>io.metersphere</groupId> <artifactId>jmeter-plugins-dubbo</artifactId> <version>1.3.8</version> <scope>system</scope> <systemPath>${project.basedir}/lib/jmeter-plugins-dubbo-1.3.8.jar</systemPath> </dependency>
終於請求成功
在這裡插入圖片描述
結語正當我幻想著給MeterSphere提交issure,並提交pr,成為一個熱門開源專案的貢獻者,從此走上人生巔峰時。我發現MeterSphere專案上的提交記錄赫然寫著 :
"fix: 修復dubbo客戶端v2.7.7以上版本在進行泛化呼叫server端為v2.6.x以前版本時出現No Provider錯誤"
BUG其實在兩個月前被解決了…雖然沒能成為MeterSphere 的貢獻者,但是第一次透過修改原始碼來解決BUG,還是很有成就感的。