基于jvm-sandbox的imock開發指南
團隊今年的指標是為公司提供一個方法級的mock平臺, 這個重要的任務落在了我的身上。
0、明確團隊的需求
-
支持java后端服務方法級別的mock,對沒有測試環境的第三方服務進行mock,增加團隊覆蓋率。 -
啟用,返回用戶自定義的mock響應結果 -
停用,返回服務本身的結果
通過一系列調研,最終工具選型了基于 jvm-sandbox的mock服務,是Java方法級別的mock,操作就是監聽指定方法,返回指定的mock內容。
1、項目介紹
imock 包含mock-module、mock-web ,mock-module就是jvm-sandbox的模塊,需要安裝到目標應用服務器,mock-web 為mock服務后臺,imock是前后端分離,還有一個前端react 項目 imcok-web
ume_mock_backend :http://git1.local.umetrip.com/guanhongli/ume_mock_backend
ume_mock_frontend :http://git1.local.umetrip.com/guanhongli/ume_mock_frontend
2、imock使用
首先將前后端項目都跑起來,安裝依賴啥的先把環境調通。
2.1、啟動imock-web
本地環境:直接idea啟動即可
容器環境:java -jar啟動
nohup?java?-jar?/opt/applog/MskyLog/mock/mock-web.jar?>?myout.txt?2>&1?&
2.2、準備mock-module
2.2.0.本地安裝
到項目下的bin目錄執行 install-local.sh,通過腳本編譯mock-module,如需修改代碼要重新執行此腳本。
2.2.1.修改cfg
#?心跳上報配置??當環境變量沒有配置的時候使用?該配置
#?mock?服務的地址和端口
mock.host=http://172.24.146.219:8003
#?標識目標應用的名稱
app.name=test-umeapp-checkin
#?標識目標應用的環境
app.env=test-umeapp-checkin
2.2.2.拷貝到sandbox-module目錄
將cfg和mock-module拷貝到sandbox/sandbox-module目錄下。
cd?/opt/applog/MskyLog/mock
cp?/opt/applog/MskyLog/mock/mock-module.jar??/opt/app/sandbox/sandbox-module
cp?-r?/opt/applog/MskyLog/mock/cfg??/opt/app/sandbox/sandbox-module
2.2.3.拷貝到.sandbox-module目錄
cp?/opt/applog/MskyLog/mock/mock-module.jar?/opt/app/.sandbox-module
2.2.4.創建mock日志目錄
mkdir?-p?/home/jboss5/logs/sandbox/mock/
2.3、attch掛載目標應用
jps命令查看pid
cd?/opt/app/sandbox/bin/
./sandbox.sh?-p?22
2.4、查看log
2.4.1、查看sandbox.log
tailf?/opt/applog/MskyLog/sandbox/sandbox.log
2.4.2、查看mock.log
tailf?/home/jboss5/logs/sandbox/mock/mock.log
2.4.3、查看服務log
結合log和error日志來看
tailf?/opt/applog/MskyLog/UmeCki/UmeCki_info.log
tailf?/opt/applog/MskyLog/UmeCki/UmeCki_trace.log
tailf?/opt/applog/MskyLog/UmeCki/UmeCki_err.log
3、遇到的問題
3.1、mock切面問題,增加before返回
看代碼mock邏輯是在afterReturning中實現的,這樣的話是不是原代碼邏輯還是會執行,只是修改了返回給調用方的Object或者Exception。比如我想mock調用銀行支付邏輯,但是還是會實際支付,所以切面放在before(Advice advice)并且結合returnImmediately會不會效果更好。
作者的代碼afterReturning方法是通過advice.getReturnObj().getClass()來獲取類,然后把ro.getReturnData()序列化到對象中。
-
如果before方法,則advice.getReturnObj()為空,空指針無法獲取類對象。 -
如果mock方法的值返回為空,則依然無法獲取對象類型。
因此需要換一個方法獲取類對象
使用advice.getTarget()方法來獲取對象類型,使用advice.getBehavior()獲取方法名稱。
Method?method?=?advice.getTarget().getClass().getMethod(advice.getBehavior().getName());
returnType?=?method.getGenericReturnType();
LogUtil.info2("returnType=",?String.valueOf(returnType));
Object?res1?=?JSON.parseObject(ro.getReturnData(),?returnType);
LogUtil.info2("res1=",?res1.toString());
但經過測試只有springboot可以用,dubbo接口advice.getTarget()為空。
在 Dubbo 中,
advice.getTarget()
返回null
可能是由于 Dubbo 的代理機制導致的。Dubbo 使用代理對象來實現遠程服務的調用,代理對象是在運行時動態生成的,而真正的目標對象是通過 Dubbo 的遠程調用機制獲取的。因此,在 Dubbo 的 Advice 中,advice.getTarget()
返回的是代理對象,而不是真正的目標對象。由于代理對象并不是目標對象本身,因此可能返回null
。在 Spring Boot 中,
advice.getTarget()
返回的是目標對象,因為 Spring Boot 使用的代理機制與 Dubbo 不同。Spring Boot 中的 AOP 代理通常是通過 JDK 動態代理或 CGLIB 生成的,這些代理對象會保留對目標對象的引用,因此在 Advice 中調用advice.getTarget()
可以獲取到目標對象的引用,不會返回null
。
接著找其他的辦法。。。
通過advice.getBehavior().getReturnType()
Method?method?=?advice.getBehavior().getReturnType().getMethod(advice.getBehavior().getName());
完美解決!
//?獲取方法的返回對象類型
Object?res1?=?JSON.parseObject(ro.getReturnData(),?advice.getBehavior().getReturnType());
LogUtil.info2("res1=",?res1.toString());
3.2、報錯time字段不為空
解決辦法:修改數據庫讓字段可以為空。
3.3、imock-web
java.lang.TypeNotPresentException: Type org.springframework.boot.maven.RepackageMojo not present
4、說在后面
至此,通過本地調試,二次開發imock已經能夠符合我們公司的需求,后續再針對個性化的需求進行開發。
- END -本文由 mdnice 多平臺發布