JavaParser抽取测试用例对应的被测方法

背景介绍

博主目前要做的工作需要将一个java项目的所有RD手写的测试用例和被测方法对应起来,最后将得到的结果存入一个json文件。

本教程以项目GitHub - binance/binance-connector-java 为例。

结果展示

最终会得到一个 funcTestMap.json,里面存放着focal func(被测方法)和对应的test case.

实现原理

1. 解析被测项目的src\main目录下的源码,将每一个java源文件中的方法声明(MethodDeclaration)存进一个map,其中key是方法名,value是完整方法题。

2. 解析被测项目的src\test\java\unit目录下的测试文件,对于每一个测试文件中的方法声明,如果方法名以"test"开头,则认为是测试用例,进入下一步。

3. 解析每一个测试用例,获取该测试用例的调用的所有方法MethodCallExpr,如果该方法存在第一步所得到的map当中,则认为该方法是测试用例的被测方法,和测试用例一起存入结果json数组中。

局限性

没有考虑到overload的情况。由于是根据方法名称而不是名称+参数类型作为方法的标识符。在存入阶段,遇到重载的方法,后面进的会覆盖掉之前的;在召回阶段,仅仅使用方法名称来查找方法体,有一定的几率找到错误的被测方法。

完整代码

项目结构如下

JsonCreator.java

package org.example;import com.github.javaparser.ast.body.MethodDeclaration;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.Map;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.charset.StandardCharsets;public class JsonCreator {public static void createAndSaveJson1(Map<String, MethodDeclaration> map, String saveJsonPath) {JsonArray jsonArray = new JsonArray();for (Map.Entry<String, MethodDeclaration> entry : map.entrySet()) {JsonObject keyValue = new JsonObject();keyValue.addProperty("key", entry.getKey());keyValue.addProperty("value", String.valueOf(entry.getValue()));jsonArray.add(keyValue);}Gson gson = new GsonBuilder().setPrettyPrinting().create();String jsonOutput = gson.toJson(jsonArray);try {Files.write(Paths.get(saveJsonPath), jsonOutput.getBytes(StandardCharsets.UTF_8));System.out.println("JSON file saved successfully to " + saveJsonPath);} catch (Exception e) {System.err.println("Error writing JSON to file: " + e.getMessage());}}public static void createAndSaveJson2(Map<MethodDeclaration, MethodDeclaration> map, String saveJsonPath) {JsonArray jsonArray = new JsonArray();for (Map.Entry<MethodDeclaration, MethodDeclaration> entry : map.entrySet()) {JsonObject keyValue = new JsonObject();keyValue.addProperty("focal func", String.valueOf(entry.getKey()));keyValue.addProperty("test case", String.valueOf(entry.getValue()));jsonArray.add(keyValue);}Gson gson = new GsonBuilder().setPrettyPrinting().create();String jsonOutput = gson.toJson(jsonArray);try {Files.write(Paths.get(saveJsonPath), jsonOutput.getBytes(StandardCharsets.UTF_8));System.out.println("JSON file saved successfully to " + saveJsonPath);} catch (Exception e) {System.err.println("Error writing JSON to file: " + e.getMessage());}}}

TestMethodAnalyzer.java

package org.example;import com.github.javaparser.ParseResult;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.comments.JavadocComment;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.github.javaparser.utils.SourceRoot;import java.io.IOException;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class TestMethodAnalyzer {private static final Map<String, MethodDeclaration> methodMap = new HashMap<>();private static final Map<MethodDeclaration, MethodDeclaration> funcTestMap = new HashMap<>();public static void main(String[] args) throws IOException {// Load and index all Java files from the main source directorySourceRoot mainSourceRoot = new SourceRoot(Paths.get("C:\\dataset\\binance-connector-java\\src\\main"));mainSourceRoot.tryToParseParallelized().forEach(TestMethodAnalyzer::indexMethodDeclarations);System.out.println("The size of the map is: " + methodMap.size());String saveJsonPath1 = "C:\\codes\\Java\\extract_func_test_pair\\src\\main\\java\\org\\methodMap.json";JsonCreator.createAndSaveJson1(methodMap,saveJsonPath1);// Now parse the test filesSourceRoot testSourceRoot = new SourceRoot(Paths.get("C:\\dataset\\binance-connector-java\\src\\test\\java\\unit"));testSourceRoot.tryToParseParallelized().forEach(TestMethodAnalyzer::analyzeTestClass);System.out.println("The size of the map is: " + funcTestMap.size());String saveJsonPath2 = "C:\\codes\\Java\\extract_func_test_pair\\src\\main\\java\\org\\funcTestMap.json";JsonCreator.createAndSaveJson2(funcTestMap,saveJsonPath2);}private static void indexMethodDeclarations(ParseResult<CompilationUnit> result) {result.ifSuccessful(cu -> cu.findAll(MethodDeclaration.class).forEach(md -> {md.setJavadocComment((JavadocComment) null);methodMap.put(md.getNameAsString(), md);}));}public static void analyzeTestClass(ParseResult<CompilationUnit> result) {result.ifSuccessful(cu -> {cu.accept(new VoidVisitorAdapter<Void>() {@Overridepublic void visit(MethodDeclaration md, Void arg) {super.visit(md, arg);if (md.getNameAsString().startsWith("test")) {analyzeTestMethods(md);}}}, null);});}private static void analyzeTestMethods(MethodDeclaration md) {List<MethodCallExpr> methodCalls = md.findAll(MethodCallExpr.class);for (MethodCallExpr call : methodCalls) {MethodDeclaration method = methodMap.get(call.getNameAsString());if (method != null) {System.out.println("Test Method: ");System.out.println(md);System.out.println("Calls Method body:");method.setJavadocComment((JavadocComment)null);System.out.println(method);System.out.println("---------------------------------------");funcTestMap.put(method,md);}}}}

maven依赖

只有两个(位于pom.xml)

<dependencies><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.10.1</version></dependency><dependency><groupId>com.github.javaparser</groupId><artifactId>javaparser-symbol-solver-core</artifactId><version>3.26.0</version></dependency>
</dependencies>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/862858.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Android面试八股文】Android组件内核面试题:Intent显示跳转与隐式跳转,如何使用?

文章目录 1.显示意图与隐式意图的区别,说说你的简单理解?1.1 显式意图(Explicit Intent)1.2 隐式意图1.3 显式意图和隐式意图的应用场景2.你在工作中,留意过在Android中Intent显示跳转和隐式跳转,如何使用?2.1 显式 Intent 调用2.2 Intent隐式跳转 Action2.3 Intent隐式…

快速清理Word中的嵌套表格

实例需求&#xff1a;Word文档中表格有的单元格中包含嵌套表格&#xff08;注意其中表格中有合并单元格&#xff09;&#xff0c;如下图所示。 现在需要删除单元格顶部的嵌套表格&#xff08;如上图中的表格1和表格3&#xff09;&#xff0c;如下图所示&#xff0c;如果表格较多…

整合Spring Boot和Apache Solr进行全文搜索

整合Spring Boot和Apache Solr进行全文搜索 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在现代应用开发中&#xff0c;全文搜索是许多应用不可或缺的功能之…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 数字排列游戏(200分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f…

Elasticsearch-Rest-Client

Elasticsearch-Rest-Client&#xff1a;官方RestClient&#xff0c;封装了ES操作&#xff0c;API层次分明&#xff0c;上手简单。 1. 导入依赖 <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high…

14-6 小型语言模型在商业应用中的使用指南

人工智能 (AI) 在商业领域的发展使众多工具和技术成为人们关注的焦点&#xff0c;其中之一就是语言模型。这些大小和复杂程度各异的模型为增强业务运营、客户互动和内容生成开辟了新途径。本指南重点介绍小型语言模型、它们的优势、实际用例以及企业如何有效利用它们。 基础知识…

Windows 系统 Solr 8.11.3 安装详细教程(最新)

Windows 系统 Solr 8.11.3 安装详细教程 说明什么是Solr下载与解压如何启动启动命令&#xff1a;浏览器中打开dashboard其他命令查看关闭命令 说明 本次只是简单安装&#xff0c;为了在项目中使用&#xff0c;如果在公开服务器中安装需要更改开放端口&#xff0c;配置权限等。 …

Python28-1 机器学习算法之决策树

决策树&#xff08;Decision Tree&#xff09; 决策树算法是一种常用的机器学习算法&#xff0c;属于监督学习范畴。它可以用于分类和回归任务&#xff0c;具有易于理解和解释的特点。决策树通过递归将数据分割成更小的子集&#xff0c;构建一个树形结构&#xff0c;其中每个节…

visionOS 2 Beta 2的操作系统更新的介绍

应用位置调整:应用可以移动到CompatibleApps文件夹外,提供更灵活的界面布局,提升用户个性化体验。 全屏视频倾斜:全屏视频在倾斜时可以重新定位,提供更好的观看视角,增强舒适度和沉浸感。 环境卸载:长按可卸载HomeView中的环境,优化系统资源管理,提高设备运行效率。 增…

iOS开发中用到的自定义UI库

文章目录 前言cell 左右滑动菜单日历组件仿QQ 侧滑抽屉仿探探、陌陌的卡牌滑动库头部缩放视图自定义UITabbar刮刮乐广告横幅 前言 本文中的UI组件&#xff0c;是作者在移动应用开发中都用到过的。 确实&#xff0c;找到对的三方库可以快速帮助我们构建App, 极大程度上提高了生…

Websocket在Java中的实践——最小可行案例

大纲 最小可行案例依赖开启Websocket&#xff0c;绑定路由逻辑类 测试参考资料 WebSocket是一种先进的网络通信协议&#xff0c;它允许在单个TCP连接上进行全双工通信&#xff0c;即数据可以在同一时间双向流动。WebSocket由IETF标准化为RFC 6455&#xff0c;并且已被W3C定义为…

C++ | Leetcode C++题解之第204题计数质数

题目&#xff1a; 题解&#xff1a; class Solution { public:int countPrimes(int n) {vector<int> primes;vector<int> isPrime(n, 1);for (int i 2; i < n; i) {if (isPrime[i]) {primes.push_back(i);}for (int j 0; j < primes.size() && i …

深入解析:如何在 Postman 中添加请求的 Body 数据

在现代软件开发中&#xff0c;API 测试是一个不可或缺的环节&#xff0c;而 Postman 作为一款流行的 API 开发工具&#xff0c;它提供了丰富的功能来帮助开发者测试和调试 API。其中&#xff0c;添加请求的 Body 数据是发送 POST 或 PUT 请求时的一个常见需求。本文将详细讲解如…

【建设方案】工单系统建设方案(Word原件)

工单管理系统解决方案 1、工单创建&#xff1a;根据告警信息创建工单。 2、工单管理&#xff1a;列表形式展示所有工单信息及进度状态。 3、工单处理&#xff1a;对接收的工单进行处理反馈。 4、工单催办&#xff1a;根据工单时效自动发送工单催办消息通知。 5、工单归档&#…

Allegro如何单独导出一个封装?

Allegro如何单独导出一个封装? Allegro如何导出封装? 在用Allegro进行PCB设计时,有时候需要从其它的项目中导出需要的封装,但一般情况下不需要全部的封装,只需要其中的某一个封装,那么怎么导出呢? 具体操作方法如下 首先需要在Allegro的安装目录下安装两个文件。(文件附…

css 流动边框

一、背景流动边框 实现原理&#xff1a; 用背景进行旋转&#xff0c;超出我们想显示的范围则hidden&#xff0c;就有以上的效果&#xff0c;可以用after或者before元素来实现也可以。 <!DOCTYPE html> <html lang"en"><head><meta charset&qu…

Ubuntu-22.04 安装Confulence

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

第四节:如何使用注解方式从IOC中获取bean(自学Spring boot 3.x的第一天)

大家好&#xff0c;我是网创有方&#xff0c;上一节学习了如何理解Spring的两个特性IOC和AOP&#xff0c;这一节来基于上节的内容进行一个简单实践。这节要实现的效果是通过IOC容器获取到Bean&#xff0c;并且将Bean的属性显示打印出来。 第一步&#xff1a;创建pojo实体类stu…

操作系统之《处理器机调度算法》【知识点+详细解题过程】

目录 PS:处理机调度算法相关公式&#xff1a; 1、【FCFS】先来先服务调度算法 2、【SJF&#xff08;SPF&#xff09;】短作业&#xff08;进程&#xff09;优先调度算法 3、【HRRF】最高响应比优先算法 4、【SRTF】最短剩余时间优先调度算法&#xff08;抢占式&am…

SpringCloudAlibaba基础四 微服务调用组件OpenFeign

JAVA 项目中如何实现接口调用&#xff1f; 1&#xff09;Httpclient HttpClient 是 Apache Jakarta Common 下的子项目&#xff0c;用来提供高效的、最新的、功能丰富的支持 Http 协议的客户端编程工具包&#xff0c;并且它支持 HTTP 协议最新版本和建议。HttpClient 相比传统 …