精準測試:基於 asm+javaparser 呼叫鏈差異化對比實踐
適用人群
如果你也面臨這些問題
接觸到的測試都是比較偏向底層,中臺化的服務,對上層業務會比較陌生
日常開發提交測試點時會出現遺漏的情況,導致測試階段漏測
開發測試比高,經常多個開發對一個測試,且日常發版頻繁
想自己搞一套精準測試框架輔助測試
那麼你可能也需要這麼一套精準測試思路,幫助你精準且快速的進行日常測試
依賴技能樹
在早幾年前就瞭解到可以透過一些抽象語法解析工具或框架,針對 java 專案做鏈路梳理,再透過鏈路逆向反推測試迴歸點,趁著這個機會,較為深入的梳理了一下相關的知識體系
掌握:java 程式設計,瞭解 jvm 大致原理,特別編譯階段,類載入階段
熟悉:asm,可將 class 檔案梳理為一條完整的呼叫鏈
熟悉:javaparser,可將 java 檔案解析為抽象語法樹(AST)
對標前幾年大肆推的 jacoco 用於精準測試,透過 AST 解析有以下優勢
- jacoco 只告訴你執行過程中程式碼的哪些行沒覆蓋,具體這行有什麼意義,為什麼要覆蓋,怎麼去覆蓋,這些你都無從得知;而透過呼叫鏈差異對比可更為精準的推送需要回歸的業務
- jacoco 大多隻能適用於單元測試,如果想整合測試使用還需要依賴 agent 注入;而透過呼叫鏈差異對比可透過接入 jenkins 在提測前就輸出測試點,不需要改動業務程式碼
- 相比 jacoco 拿來就可以用,需要了解更多的 jvm 基礎知識,同時擴充了個人知識體系
實踐
- 呼叫鏈掃描
- 加強 Class/Method 事件篩選器,儲存父子方法呼叫關係
- 透過遍歷特性分支編譯後的 class 檔案,再透過事件生成器啟動,觸發類/方法篩選器事件
- 最終只輸出指定型別方法的呼叫鏈,包括:RPC 介面,HTTP 介面,定時任務,MQ 生產與消費
關鍵程式碼
1. asm構建classReader的方式不僅可以透過已載入的類名指定,也可以透過輸入流(InputStream),這就使得透過直接遍歷專案編譯過的.class解析呼叫鏈變為可能
FileHelper.getFilePaths(classPath, dir, ".class"); // 遍歷編譯後的build/class路徑下的所有.class檔案
classPath.forEach(c->{
ClassReader classReader = new ClassReader(new FileInputStream(c));
ClassSpider classSpider = new ClassSpider(methodInvokeInfos);
classReader.accept(classSpider, org.objectweb.asm.ClassReader.SKIP_FRAMES);
}
2. 掃描的目的是逆推對外暴露需要回歸的功能,例如介面,定時器,訊息佇列等,所以需要排除掉一些無關的鏈路
例如dubbo,thrift,job,nsq在編寫中其類一般都或有特定的註解,或有特定的父類,或有特定實現的介面型別,所以可以在類刪選器classvisiotr中進行篩選
public AnnotationVisitor visitAnnotation(String annotation, boolean b) {
if (annotation.endsWith("RestController;")) {
flag = "HTTP"
}
return super.visitAnnotation(annotation, b);
}
- 分支差異對比
- 遍歷 master、branch 路徑專案下的所有.java 檔案,生成抽象語法樹,並做去噪處理(空格,註釋等無關改動)
- 對比方法(註解,簽名,返回值,以及方法體),統計特性分支改動的方法
關鍵程式碼
1. 先比對有差異的檔案,這裡直接比對檔案大小,以及是否存在新增的java檔案,收攏第二步的篩選範圍
branch.forEach( (rp, b) -> {
if (!master.containsKey(rp)) {
b.setStatus(Status.NEW);
} else {
JavaFileInfo m = master.get(rp);
if (b.getLength() != m.getLength()){
b.setStatus(Status.MODIFY);
m.setStatus(Status.MODIFY);
}
}
});
master.forEach( (rp, m) -> {
if (!branch.containsKey(rp)) {
m.setStatus(Status.DELETE);
}
});
2. 遍歷branch 和 master路徑下修改過或新增的.java檔案,生成AST
CompilationUnit cu = StaticJavaParser.parse(file);
List<Comment> comments = cu.getAllContainedComments(); // 這裡開始去除無關注釋
List<Comment> unwantedComments = comments
.stream()
.filter(p -> !p.getCommentedNode().isPresent() || p instanceof LineComment)
.collect(Collectors.toList());
unwantedComments.forEach(Node::remove);
VoidVisitor<List<ClassParser>> classParserVoidVisitor = new VisitorPrinter();、
classParserVoidVisitor.visit(cu, classParsers); // 遍歷檔案,儲存語法樹
3. 對比差異化,輸出特性分支修改/新增的方法
masterMethod.checkAnnotationEqual(branchMethod).checkTypeEqual(branchMethod).checkBodyEqual(bbranchMethod); // 這裡我主要比對了方法的註解,詳情就不展開了
- 呼叫鏈&差異化輸出
- 遍歷呼叫鏈與上述差異化方法,輸出需要回歸的指定方法/介面
- 附帶資訊可包括:統計改動了多少行程式碼,改動的型別(包括:返回值改動,註解改動,新增方法,方法體變更),以及對應改動點
- 呼叫鏈入庫,並提供介面供查詢 或 回撥特定介面
- 可將介面與日常手工迴歸的案例/自動化案例做匹配,這樣精準測試可以提送指定的案例用於迴歸&測試
相關文章
- 基於知識圖譜的呼叫鏈分析精準化測試平臺
- 精準測試實踐
- 得物商家域精準測試實踐
- list對比差異
- 基於 AI 大模型的精準測試分享AI大模型
- MySQL效能基準測試對比:5.7 VS 8.0MySql
- 基於postman的api自動化測試實踐PostmanAPI
- vue-codemirror 實現文字差異比對Vue
- 文字內容差異對比
- 精準化測試原理簡介
- 精準測試
- Android Gradle基於引數化配置實現差異化構建AndroidGradle
- 基於介面資料變異的App健壯性測試實踐APP
- 集合差異比較演算法及效能測試演算法
- 精準測試與開源工具Jacoco的覆蓋率能力對比開源工具
- 中美慈善基金會差異對比
- 高德全鏈路壓測——精準控壓的建設實踐
- 差異巨大 6款通用工業級ARM處理器效能測試對比
- 基於混合雲管理標準化模型,消除差異化與互操作性難題模型
- 錄製回放效果差異檢測 | 自動化測試
- 異常測試實踐與梳理
- 文字差異對比工具 go-diffGo
- APM呼叫鏈產品對比
- 精準測試案例展示
- hadoop基準測試_Hadoop TeraSort基準測試Hadoop
- 【Python】Python 對比 C語言的差異PythonC語言
- Git比對檔案之間的差異Git
- openGauss資料與PostgreSQL的差異對比SQL
- PostgreSQL TPROC-C基準測試:PostgreSQL 12與PostgreSQL 13效能對比SQL
- Python自動化:智慧對比Word文件,秒速鎖定差異!Python
- 簡單對比測試了幾個基於 swoole 的框架框架
- 公告:關於精準測試一些雜事
- 基準測試
- Mac 上超好用的程式碼對比工具 beyond compare,對比json差異MacJSON
- 精準測試之覆蓋
- git 本地對比2次commit直接的差異GitMIT
- 開發者測試-採用精準測試工具對Spring Boot應用進行測試Spring Boot
- Jest基於dva框架的單元測試最佳實踐框架