Compare commits

...

127 Commits

Author SHA1 Message Date
liangdaliang
59d0031f75 Merge remote-tracking branch 'origin/master' 2025-07-01 16:37:12 +08:00
liangdaliang
d960cb6553 修改前端新打开tab不能刷新的问题及适配性能测试http端口null的问题 2025-07-01 16:36:23 +08:00
pfl
af54b475a2 fix:测试计划报告最后更新时间显示问题修复 2025-07-01 10:06:33 +08:00
pfl
c12be119a3 add:测试计划关联测试报告编辑API 2025-06-27 18:25:56 +08:00
pfl
924f5a935f 测试计划关联测试报告界面调整 2025-06-26 16:19:57 +08:00
pfl
963e9a8162 fix:测试计划进度显示sql修改 2025-06-25 18:12:55 +08:00
pfl
5296b22534 add:测试计划执行用例报告删除api 2025-06-25 16:11:54 +08:00
pfl
48b20390d4 Merge remote-tracking branch 'origin/master' 2025-06-25 13:51:17 +08:00
pfl
ef741fcb64 fix:测试计划新建报告及报告详情显示 2025-06-25 13:50:21 +08:00
liangdaliang
c170f9e5ec 解决Jmeter异常日志不显示问题 2025-06-24 10:49:09 +08:00
f9774b7eef fix 修改测试路径修改 2025-06-23 17:44:30 +08:00
pfl
ef4d51876f Merge remote-tracking branch 'origin/master' 2025-06-23 17:36:05 +08:00
pfl
737aaf4482 fix:测试计划界面列表显示问题修复 2025-06-23 17:35:27 +08:00
c0f0b96487 fix 路由修改 2025-06-23 17:21:59 +08:00
liangdaliang
ca1e8182db 解决迭代次数为0时问题 2025-06-23 16:55:11 +08:00
pfl
f8b935378f 测试计划关联用例
测试报告界面
2025-06-23 15:51:34 +08:00
660871f873 fix 修改截图路径 2025-06-19 18:04:31 +08:00
cfdc292c1d fix 修改截图路径 2025-06-19 17:13:30 +08:00
liangdaliang
49d63847ee 性能测试增加执行人 2025-06-17 10:05:48 +08:00
liangdaliang
efa41a7217 数据库sql查询支持上下文变量 2025-06-16 17:04:18 +08:00
0f25043d8c fix 压力测试bug修改 2025-06-16 15:04:04 +08:00
c9e2aa7c57 fix 数据提取第二步提取的参数,在第五步里用不了 2025-06-13 16:28:57 +08:00
liangdaliang
e0910ea033 redis配置及jmeter持续时长默认值 2025-06-13 16:16:34 +08:00
ffed752170 fix 打开一个测试报告后,再打开另外一个测试报告,显示的还是之前打开的测试报告 2025-06-13 15:45:52 +08:00
614aa05b42 fix 场景步骤删除后,右边的页面没有清空 2025-06-13 15:09:59 +08:00
liangdaliang
7161354894 适配定时任务调度改造 2025-06-09 14:42:18 +08:00
liangdaliang
c6380b6bde 修改数据库连接 2025-06-09 10:58:10 +08:00
liangdaliang
f394dc4590 删除无效的引入包 2025-06-09 10:21:55 +08:00
pfl
5cc2cdfc34 测试计划概览前端及后端代码完善 2025-06-06 17:19:18 +08:00
eee51078b5 fix 截图动作放到后置操作结束后截图 2025-06-06 11:22:44 +08:00
74457d2c81 fix 解决任务进去场景列表里都变成失效了,打开保存后重新进去也还是失效bug 2025-06-06 09:33:39 +08:00
a790ffbcba feat 前面步骤中提取的参数,需要支持在后续步骤中引用 2025-06-03 14:14:41 +08:00
pfl
eb58fd40c7 测试报告倒序及分页修复 2025-06-03 11:12:08 +08:00
pfl
c6a73afb76 1、需求详情前后端代码完善
2、缺陷管理详情前后端代码完善
2025-05-30 17:58:46 +08:00
606c3c15ea fix ui场景列表前端执行结果显示问题修复 2025-05-30 17:54:55 +08:00
d54b4523bf fix 压力测试添加更严格的cron表达式验证 2025-05-29 11:44:54 +08:00
3fad8f3a5a fix 断言支持配置失败后是否继续执行和 定时任务配置完成后,有下次执行时间,保存重新进来后没有下次执行时间 2025-05-29 11:27:08 +08:00
liangdaliang
3209f1e35c 时间格式化 2025-05-29 10:33:23 +08:00
liangdaliang
75fcd51dea 解决异步执行线程卡住问题 2025-05-28 19:02:53 +08:00
a9d0f68f52 ui自动化报表截图查看 2025-05-28 18:20:06 +08:00
e5dc3bab05 ui自动化编辑回到列表不刷新列表 2025-05-28 18:02:10 +08:00
080a80d53d ui自动化和压力测试bug修改 2025-05-28 16:31:27 +08:00
liangdaliang
66498fd750 解决排序问题 2025-05-28 15:04:18 +08:00
8636842735 ui自动化执行问题处理 2025-05-28 13:55:16 +08:00
liangdaliang
66c627d33a 解决测试计划性能测试相关bug 2025-05-28 13:54:43 +08:00
liangdaliang
c71b9d8c63 解决测试计划性能测试相关bug 2025-05-28 13:24:19 +08:00
426ee6aae9 自动化测试定时任务 2025-05-28 10:45:35 +08:00
0960370562 ui测试前后端问题修复 2025-05-27 16:09:35 +08:00
a3c140db47 ui测试前后端问题修复 2025-05-27 15:14:40 +08:00
64b57fc3ec ui测试前后端问题修复 2025-05-27 14:32:09 +08:00
2965095148 ui测试前后端问题修复 2025-05-27 09:18:47 +08:00
e7248e613a fix:断言 2025-05-26 11:18:23 +08:00
441f7d041d 场景执行bug修改 2025-05-12 13:24:50 +08:00
85decf2a60 场景执行bug修改 2025-05-12 11:07:50 +08:00
c07742651d 场景执行bug修改 2025-05-12 10:44:24 +08:00
a3e13b3972 场景执行bug修改 2025-05-12 10:19:21 +08:00
78cb16fd19 场景执行bug修改 2025-05-12 10:11:05 +08:00
c99f639976 高级设置显示排序 2025-05-08 15:55:08 +08:00
56d4a24e81 fix:修复场景新增编辑,数据提取问题 2025-05-08 15:22:15 +08:00
09c9c4eaec 场景新增bug修改 2025-05-08 13:12:49 +08:00
898fc59b50 add:ui测试,编辑和新增api 2025-05-07 17:31:17 +08:00
fa30bb8bc5 执行高级设置 断言和数据提取 2025-05-07 16:41:21 +08:00
d1b00e3ebf 解决场景详情显示bug 2025-05-07 16:41:20 +08:00
pfl
219c6f4e8d 测试计划接口调整 2025-05-07 14:41:23 +08:00
pfl
d3cd149ca5 测试计划关联测试缺陷完善 2025-05-06 18:51:57 +08:00
pfl
7afae71c8a 测试计划关联报告前端修改 2025-05-06 09:46:03 +08:00
pfl
2502520829 测试计划关联报告前端修改 2025-04-30 14:21:52 +08:00
pfl
0c250601ec 测试计划前端及后端代码完善 2025-04-29 21:44:04 +08:00
59aca2920c fix:自动化测试-场景编辑 2025-04-29 17:56:11 +08:00
8e6095820f ui自动化场景传参参数修改 2025-04-29 16:49:30 +08:00
b0427ef35c add: ui测试- 自动化-编辑-场景步骤 2025-04-29 15:08:14 +08:00
2d8be3482a ui自动化执行接口 2025-04-28 17:00:42 +08:00
5442c6b688 chromedriver路径配置 2025-04-28 11:29:03 +08:00
326e21292f add :自动化 - 执行api 2025-04-28 09:31:05 +08:00
liangdaliang
18434d1f88 测试计划关联用例及执行 2025-04-27 23:36:48 +08:00
pfl
b680339e6a 测试计划列表显示完善 2025-04-27 19:14:55 +08:00
354a65938a add:UI测试-测试报告列表api,测试报告详情api,自动化列表api 2025-04-27 18:09:51 +08:00
d71d5c070e UI执行接口 2025-04-27 14:19:12 +08:00
83109f3170 add: 测试报告-元素库-修改 2025-04-27 14:04:59 +08:00
pfl
2e5736d045 测试报告接口前缀修改 2025-04-27 13:52:06 +08:00
75b83d2847 add:元素库 - api 2025-04-27 13:36:36 +08:00
pfl
bbb9cb26f9 1、测试计划关联需求列表查询
2、测试计划关联报告列表查询
2025-04-25 18:31:44 +08:00
pfl
5ce3f5c64b 测试计划相关接口 2025-04-25 10:36:38 +08:00
0a79684d86 add:ui自动化-场景 2025-04-25 10:30:26 +08:00
addbe3ecd4 UI报告接口 2025-04-25 10:22:21 +08:00
liangdaliang
7627042c4d 用例测试校验规则完善 2025-04-24 17:37:07 +08:00
温若烈酒慕茶凉丷
17d8fa4083 add:UI测试-测试报告详情 2025-04-24 17:10:12 +08:00
liangdaliang
78cbb5aaaf 自动化测试执行日志和操作日志功能 2025-04-24 16:33:06 +08:00
pfl
814a7a39d2 需求删除逻辑修改 2025-04-24 16:01:28 +08:00
liangdaliang
f2be0e33b0 Jmeter请求增加顺序执行 2025-04-24 12:34:36 +08:00
liangdaliang
d5b6341b21 Jmeter Json提取 2025-04-24 09:15:40 +08:00
bfea486350 UI 自动化场景 场景步骤接口 2025-04-23 17:53:09 +08:00
c5e18b985f add:UI测试-元素库,自动化列表 2025-04-23 17:28:38 +08:00
liangdaliang
5ae19a8847 缺陷管理BUG修复 2025-04-23 14:52:05 +08:00
liangdaliang
56ffeb2f05 缺陷管理 2025-04-23 13:13:20 +08:00
温在好
218d2b3026 Merge branch 'master' of http://ah.qyyh.net:3000/xiaoe/test 2025-04-22 20:07:55 +08:00
温在好
953b06a9bc SeleniumUtils工具类提交 2025-04-22 20:07:29 +08:00
b1e05e0334 元素库接口增删改查 2025-04-22 16:59:53 +08:00
4babf44054 fix:性能测试-测试 2025-04-21 17:19:25 +08:00
liangdaliang
19640f99f7 UI测试工具类初步提交演示 2025-04-21 11:58:08 +08:00
liangdaliang
051d66d1f9 UI测试工具类初步提交 2025-04-21 11:40:34 +08:00
97e74dd4ca add: 性能测试-报告 2025-04-21 10:54:16 +08:00
pfl
f677776c31 需求新增导出及批量导出接口 2025-04-18 17:05:35 +08:00
pfl
497ff672d1 需求编辑接口bug修复 2025-04-18 14:41:54 +08:00
liangdaliang
c91a6183ba 优化统计效率 2025-04-18 13:29:11 +08:00
defa663b4c 性能测试接口删除时移除定时任务 2025-04-18 11:30:56 +08:00
liangdaliang
cacba80269 Merge remote-tracking branch 'origin/master' 2025-04-18 11:22:04 +08:00
liangdaliang
58021edcb7 分页bug 2025-04-18 11:21:39 +08:00
bc0b83c828 性能测试接口定时任务 2025-04-18 11:13:48 +08:00
liangdaliang
6d4e38b1fd jmeter性能测试及报告功能全量提交 2025-04-18 10:56:21 +08:00
pfl
e160bd8866 需求接口完善 2025-04-18 09:56:54 +08:00
03144f2a7b add:性能测试-报告 2025-04-17 17:29:59 +08:00
pfl
62f9dd359f 需求功能前后端代码实现 2025-04-17 17:13:33 +08:00
7645801fcb 性能测试接口詳情接口 2025-04-17 14:27:29 +08:00
fanzhuxian
87bb3af12c add:性能测试-测试 2025-04-17 10:55:01 +08:00
liangdaliang
adbceebec5 jmeter性能测试及报告功能全量提交 2025-04-16 18:26:17 +08:00
f200aeec4e 性能测试接口修改并执行接口 2025-04-16 17:38:04 +08:00
4186fef45a 性能测试接口测试用例查询修改 2025-04-16 14:58:22 +08:00
8cd31c07f6 性能测试接口查询修改 2025-04-15 15:56:57 +08:00
f9b050a569 性能测试接口 2025-04-15 13:34:55 +08:00
949322600d 性能测试接口 2025-04-15 13:32:27 +08:00
liangdaliang
cb7a7c947c jmeter性能测试及报告初步提交 2025-04-15 11:57:12 +08:00
082094d9ef 性能测试实体类类型修改 2025-04-15 09:20:29 +08:00
d0d195c69c 性能测试基础配置 2025-04-14 15:57:39 +08:00
liangdaliang
33bf583dab 任务执行记录列表和操作日志列表接口提交 2025-03-24 10:46:08 +08:00
liangdaliang
b4c89d3b9a 测试用例执行相关优化 2025-03-21 16:09:53 +08:00
liangdaliang
2addbd2179 用例提取为全局变量可引用 2025-03-20 18:13:18 +08:00
229 changed files with 27748 additions and 251 deletions

View File

@@ -6,16 +6,16 @@ spring:
druid:
# 主库数据源
master:
url: jdbc:mysql://47.103.142.5:3306/cmcf-test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: test
password: Test123@
url: jdbc:mysql://120.27.225.67:9609/riskmanage?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: riskmanage
password: riskmanage@Farben2023
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
@@ -39,7 +39,7 @@ spring:
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
webStatFilter:
enabled: true
statViewServlet:
enabled: true
@@ -58,4 +58,4 @@ spring:
merge-sql: true
wall:
config:
multi-statement-allow: true
multi-statement-allow: true

View File

@@ -12,7 +12,9 @@ test:
addressEnabled: true
# Jmeter主目录路径
jmeterHomePath: /opt/apache-jmeter
#chromedriver路径
selenium:
chrome-driver-path: /usr/local/bin/chromedriver
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
@@ -69,13 +71,13 @@ spring:
# redis 配置
redis:
# 地址
host: ah.qyyh.net
host: 47.99.93.74
# 端口默认为6379
port: 15129
port: 6379
# 数据库索引
database: 1
# 密码
password:
password: foobaredDkhsb
# 连接超时时间
timeout: 10s
lettuce:

View File

@@ -157,6 +157,17 @@
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.30.0</version> <!-- 根据需要选择版本 -->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

View File

@@ -0,0 +1,36 @@
package com.test.common.core.domain.model;
/**
* @author liangdaliang
* @DescriptionHttp错误编码统计结果
* @date 2025-04-17 19:05
*/
public class ErrorCodeStat {
private final String responseCode;
private final Long count;
private final Double errorRatio; // 占所有错误的比率
private final Double totalRatio; // 占所有请求的比率
public ErrorCodeStat(String responseCode, long count, double errorRatio, double totalRatio) {
this.responseCode = responseCode;
this.count = count;
this.errorRatio = errorRatio;
this.totalRatio = totalRatio;
}
public String getResponseCode() {
return responseCode;
}
public Long getCount() {
return count;
}
public Double getErrorRatio() {
return errorRatio;
}
public Double getTotalRatio() {
return totalRatio;
}
}

View File

@@ -0,0 +1,47 @@
package com.test.common.core.domain.model;
import java.util.List;
/**
* @author liangdaliang
* @Description总体错误信息统计
* @date 2025-04-17 19:50
*/
public class ErrorTotalStats {
/**
* 错误响应状态码统计列表
*/
private List<ErrorCodeStat> errorCodeStatList;
/**
* Top 5错误接口列表
*/
private List<InterfaceErrorStat> top5InterfaceErrorStatList;
/**
* 每个接口的错误码明细列表
*/
private List<InterfaceErrorDetail> interfaceErrorDetailList;
public List<ErrorCodeStat> getErrorCodeStatList() {
return errorCodeStatList;
}
public void setErrorCodeStatList(List<ErrorCodeStat> errorCodeStatList) {
this.errorCodeStatList = errorCodeStatList;
}
public List<InterfaceErrorStat> getTop5InterfaceErrorStatList() {
return top5InterfaceErrorStatList;
}
public void setTop5InterfaceErrorStatList(List<InterfaceErrorStat> top5InterfaceErrorStatList) {
this.top5InterfaceErrorStatList = top5InterfaceErrorStatList;
}
public List<InterfaceErrorDetail> getInterfaceErrorDetailList() {
return interfaceErrorDetailList;
}
public void setInterfaceErrorDetailList(List<InterfaceErrorDetail> interfaceErrorDetailList) {
this.interfaceErrorDetailList = interfaceErrorDetailList;
}
}

View File

@@ -0,0 +1,42 @@
package com.test.common.core.domain.model;
/**
* @author liangdaliang
* @DescriptionHttp采样
* @date 2025-04-17 19:03
*/
public class HttpSample {
private String lb; // 接口名称
private Boolean s; // true为请求成功
private String rc; // 请求响应编码
public HttpSample(String label, Boolean s, String rc) {
this.lb = label;
this.s = s;
this.rc = rc;
}
public String getLb() {
return lb;
}
public void setLb(String lb) {
this.lb = lb;
}
public Boolean getS() {
return s;
}
public void setS(Boolean s) {
this.s = s;
}
public String getRc() {
return rc;
}
public void setRc(String rc) {
this.rc = rc;
}
}

View File

@@ -0,0 +1,27 @@
package com.test.common.core.domain.model;
import java.util.Map;
/**
* @author liangdaliang
* @Description接口错误明细
* @date 2025-04-17 19:18
*/
public class InterfaceErrorDetail {
private String interfaceName;
private Map<String, Long> errorCodeCounts;
public InterfaceErrorDetail(String interfaceName, Map<String, Long> errorCodeCounts) {
this.interfaceName = interfaceName;
this.errorCodeCounts = errorCodeCounts;
}
public String getInterfaceName() {
return interfaceName;
}
public Map<String, Long> getErrorCodeCounts() {
return errorCodeCounts;
}
}

View File

@@ -0,0 +1,36 @@
package com.test.common.core.domain.model;
/**
* @author liangdaliang
* @Description接口错误统计
* @date 2025-04-17 19:08
*/
public class InterfaceErrorStat {
private String interfaceName;
private Long totalSamples;
private Long errorCount;
private Double errorRate;
public InterfaceErrorStat(String interfaceName, long totalSamples, long errorCount) {
this.interfaceName = interfaceName;
this.totalSamples = totalSamples;
this.errorCount = errorCount;
}
public String getInterfaceName() {
return interfaceName;
}
public Long getTotalSamples() {
return totalSamples;
}
public Long getErrorCount() {
return errorCount;
}
public Double getErrorRate() {
errorRate = (totalSamples == 0 ? 0 : (double) errorCount / totalSamples * 100);
return errorRate;
}
}

View File

@@ -0,0 +1,36 @@
package com.test.common.core.domain.model;
import java.util.List;
/**
* @author liangdaliang
* @DescriptionJmeter性能测试总体报告实体类
* @date 2025-04-18 08:55
*/
public class JmeterGlobalStatEntity {
/**
* Jmeter汇总报告实体对象列表
*/
private List<LabelStatsEntity> statsEntityList;
/**
* Jmeter总体错误信息统计
*/
private ErrorTotalStats errorTotalStats;
public List<LabelStatsEntity> getStatsEntityList() {
return statsEntityList;
}
public void setStatsEntityList(List<LabelStatsEntity> statsEntityList) {
this.statsEntityList = statsEntityList;
}
public ErrorTotalStats getErrorTotalStats() {
return errorTotalStats;
}
public void setErrorTotalStats(ErrorTotalStats errorTotalStats) {
this.errorTotalStats = errorTotalStats;
}
}

View File

@@ -0,0 +1,119 @@
package com.test.common.core.domain.model;
import java.util.List;
/**
* @author liangdaliang
* @DescriptionJmeter线程组调用参数
* @date 2025-04-14 18:04
*/
public class JmeterGroupRequest {
private Long testCaseId;
private Long sid;
private Integer concurrentThreads;
private Integer errorOperType;
private Integer executeType;
private Integer rampUpSeconds;
private Long pressureSecond;
private Integer loopCount;
private Integer rpsStatus;
private Integer rpsLimit;
private String jmeterHomePath;
private List<JmeterRequest> jmeterRequestList;
public String getJmeterHomePath() {
return jmeterHomePath;
}
public void setJmeterHomePath(String jmeterHomePath) {
this.jmeterHomePath = jmeterHomePath;
}
public Integer getConcurrentThreads() {
return concurrentThreads;
}
public void setConcurrentThreads(Integer concurrentThreads) {
this.concurrentThreads = concurrentThreads;
}
public Integer getErrorOperType() {
return errorOperType;
}
public void setErrorOperType(Integer errorOperType) {
this.errorOperType = errorOperType;
}
public Integer getExecuteType() {
return executeType;
}
public void setExecuteType(Integer executeType) {
this.executeType = executeType;
}
public Integer getRampUpSeconds() {
return rampUpSeconds;
}
public void setRampUpSeconds(Integer rampUpSeconds) {
this.rampUpSeconds = rampUpSeconds;
}
public Long getPressureSecond() {
return pressureSecond;
}
public void setPressureSecond(Long pressureSecond) {
this.pressureSecond = pressureSecond;
}
public Integer getLoopCount() {
return loopCount;
}
public void setLoopCount(Integer loopCount) {
this.loopCount = loopCount;
}
public Integer getRpsStatus() {
return rpsStatus;
}
public void setRpsStatus(Integer rpsStatus) {
this.rpsStatus = rpsStatus;
}
public Integer getRpsLimit() {
return rpsLimit;
}
public void setRpsLimit(Integer rpsLimit) {
this.rpsLimit = rpsLimit;
}
public Long getTestCaseId() {
return testCaseId;
}
public void setTestCaseId(Long testCaseId) {
this.testCaseId = testCaseId;
}
public Long getSid() {
return sid;
}
public void setSid(Long sid) {
this.sid = sid;
}
public List<JmeterRequest> getJmeterRequestList() {
return jmeterRequestList;
}
public void setJmeterRequestList(List<JmeterRequest> jmeterRequestList) {
this.jmeterRequestList = jmeterRequestList;
}
}

View File

@@ -1,16 +1,26 @@
package com.test.common.core.domain.model;
import lombok.Data;
import java.util.List;
/**
* @author liangdaliang
* @DescriptionJmeter调用参数
* @date 2025-02-19 10:55
*/
@Data
public class JmeterRequest {
/**
* 用例步骤id
*/
private Long id;
/**
* 用例步骤名称
*/
private String testCaseName;
/**
* 请求完整url
*/
@@ -46,67 +56,8 @@ public class JmeterRequest {
*/
private String jmeterHomePath;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getRequestBody() {
return requestBody;
}
public void setRequestBody(String requestBody) {
this.requestBody = requestBody;
}
public String getRequestParams() {
return requestParams;
}
public void setRequestParams(String requestParams) {
this.requestParams = requestParams;
}
public String getRequestHeader() {
return requestHeader;
}
public void setRequestHeader(String requestHeader) {
this.requestHeader = requestHeader;
}
public String getJmeterHomePath() {
return jmeterHomePath;
}
public void setJmeterHomePath(String jmeterHomePath) {
this.jmeterHomePath = jmeterHomePath;
}
/**
* jmeter提取表达式
*/
private List<String> extractionRuleList;
}

View File

@@ -0,0 +1,96 @@
package com.test.common.core.domain.model;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* @author liangdaliang
* @DescriptionJmeter汇总报告实体对象
* @date 2025-04-16 14:24
*/
public class LabelStatsEntity {
private String label;
private Long samples = 0L;
private Long average = 0L;
private Long min = 0L;
private Long max = 0L;
@JsonFormat(shape = JsonFormat.Shape.NUMBER, pattern = "0.00")
private Double errorRate = 0d;
@JsonFormat(shape = JsonFormat.Shape.NUMBER, pattern = "0.0")
private Double throughput = 0d;
@JsonFormat(shape = JsonFormat.Shape.NUMBER, pattern = "0.00")
private Double receivedKBPerSec = 0d;
@JsonFormat(shape = JsonFormat.Shape.NUMBER, pattern = "0.00")
private Double sentKBPerSec = 0d;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public Long getSamples() {
return samples;
}
public void setSamples(Long samples) {
this.samples = samples;
}
public Long getAverage() {
return average;
}
public void setAverage(Long average) {
this.average = average;
}
public Long getMin() {
return min;
}
public void setMin(Long min) {
this.min = min;
}
public Long getMax() {
return max;
}
public void setMax(Long max) {
this.max = max;
}
public Double getErrorRate() {
return errorRate;
}
public void setErrorRate(Double errorRate) {
this.errorRate = errorRate;
}
public Double getThroughput() {
return throughput;
}
public void setThroughput(Double throughput) {
this.throughput = throughput;
}
public Double getReceivedKBPerSec() {
return receivedKBPerSec;
}
public void setReceivedKBPerSec(Double receivedKBPerSec) {
this.receivedKBPerSec = receivedKBPerSec;
}
public Double getSentKBPerSec() {
return sentKBPerSec;
}
public void setSentKBPerSec(Double sentKBPerSec) {
this.sentKBPerSec = sentKBPerSec;
}
}

View File

@@ -0,0 +1,50 @@
package com.test.common.enums;
/**
* @author liangdaliang
* @Description缺陷状态枚举
* @date 2025-04-23 13:59
*/
public enum EnumDefectStatus {
PENDING_CONFIRMATION("0", "待确认"),
UNDER_REPAIR("1", "修复中"),
COMPLETED("2", "已完成"),
INVALID_DEFECT("3", "无效缺陷"),
SUSPENDED("4", "挂起"),
PENDING_VERIFICATION("5", "待验证");
private final String code;
private final String description;
EnumDefectStatus(String code, String description) {
this.code = code;
this.description = description;
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
/**
* 根据状态码获取对应的枚举值
*/
public static EnumDefectStatus fromCode(String code) {
for (EnumDefectStatus status : values()) {
if (status.code.equals(code)) {
return status;
}
}
throw new IllegalArgumentException("无效的状态码: " + code);
}
/**
* 根据状态码获取中文描述(可选)
*/
public static String getDescriptionByCode(String code) {
return fromCode(code).getDescription();
}
}

View File

@@ -0,0 +1,49 @@
package com.test.common.enums;
/**
* @author liangdaliang
* @Description缺陷严重程度枚举
* @date 2025-04-23 14:06
*/
public enum EnumSeverityLevel {
INVALID("0", "无效"),
MINOR("1", "轻微"),
MODERATE("2", "一般"),
SEVERE("3", "严重"),
CRITICAL("4", "致命");
private final String code;
private final String description;
EnumSeverityLevel(String code, String description) {
this.code = code;
this.description = description;
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
/**
* 根据严重程度码获取枚举实例
*/
public static EnumSeverityLevel fromCode(String code) {
for (EnumSeverityLevel level : values()) {
if (level.code.equals(code)) {
return level;
}
}
throw new IllegalArgumentException("无效的严重程度码: " + code);
}
/**
* 根据状态码直接获取中文描述
*/
public static String getDescriptionByCode(String code) {
return fromCode(code).getDescription();
}
}

View File

@@ -8,6 +8,7 @@ import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import org.apache.commons.lang3.time.DateFormatUtils;
@@ -186,4 +187,60 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
public static String calculateTimeDifference(Date startTime, Date endTime) {
long diffInMillis = endTime.getTime() - startTime.getTime(); // 获取时间差(毫秒)
long totalSeconds = diffInMillis / 1000; // 转换为秒
long totalMinutes = totalSeconds / 60; // 转换为分钟
long totalHours = totalMinutes / 60; // 转换为小时
StringBuilder result = new StringBuilder();
// 如果时间差超过1小时
if (totalHours > 0) {
result.append(totalHours).append("h");
long remainingMinutes = totalMinutes % 60; // 剩余的分钟
if (remainingMinutes > 0) {
result.append(remainingMinutes).append("min");
}
long remainingSeconds = totalSeconds % 60; // 剩余的秒
if (remainingSeconds > 0) {
result.append(remainingSeconds).append("s");
}
} else if (totalMinutes > 0) { // 如果时间差在1分钟到1小时之间
result.append(totalMinutes).append("min");
long remainingSeconds = totalSeconds % 60; // 剩余的秒
if (remainingSeconds > 0) {
result.append(remainingSeconds).append("s");
}
} else { // 如果时间差小于1分钟
result.append(totalSeconds).append("s");
}
return result.toString();
}
/**
* 计算两个时间点的时间差(单位为毫秒)
*
* @param startTime 开始时间
* @param endTime 结束时间
* @return 时间差(单位为毫秒)
*/
public static long differenceInMilliseconds(Date startTime, Date endTime) {
if (startTime == null || endTime == null) {
throw new IllegalArgumentException("开始时间和结束时间不能为空");
}
return endTime.getTime() - startTime.getTime();
}
/**
* 格式化日期为 yyyy-MM-dd HH:mm:ss
*/
public static String formatDateTime(Date date) {
return date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime()
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
}

View File

@@ -0,0 +1,127 @@
package com.test.common.utils;
import com.test.common.core.domain.model.ErrorCodeStat;
import com.test.common.core.domain.model.HttpSample;
import com.test.common.core.domain.model.InterfaceErrorDetail;
import com.test.common.core.domain.model.InterfaceErrorStat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author liangdaliang
* @DescriptionHttp采样分析工具类
* @date 2025-04-17 19:01
*/
public class HttpSampleAnalyzer {
private final List<HttpSample> samples;
private final int totalRequests;
public HttpSampleAnalyzer(List<HttpSample> samples) {
this.samples = samples;
this.totalRequests = samples.size();
}
/**
* 需求1: 错误响应状态码统计
* @return 错误状态码统计列表
*/
public List<ErrorCodeStat> analyzeErrorCodes() {
// 过滤出所有失败的请求
List<HttpSample> errorSamples = samples.stream()
.filter(s -> !s.getS())
.collect(Collectors.toList());
int totalErrors = errorSamples.size();
// 按状态码分组统计
Map<String, Long> codeCountMap = errorSamples.stream()
.collect(Collectors.groupingBy(
HttpSample::getRc,
Collectors.counting()
));
// 转换为包含比率的统计对象
List<ErrorCodeStat> result = new ArrayList<>();
codeCountMap.forEach((code, count) -> {
double errorRatio = totalErrors == 0 ? 0 : (double) count / totalErrors * 100;
double totalRatio = (double) count / totalRequests * 100;
result.add(new ErrorCodeStat(code, count, errorRatio, totalRatio));
});
// 按错误数量降序排序
result.sort((a, b) -> Long.compare(b.getCount(), a.getCount()));
return result;
}
/**
* 需求2: Top 5错误接口统计
* @return Top 5错误接口列表
*/
public List<InterfaceErrorStat> getTop5ErrorInterfaces() {
// 获取所有接口的错误统计
Map<String, InterfaceErrorStat> allInterfaceStats = getAllInterfacesErrorStats();
// 按错误数量降序排序并取前5
return allInterfaceStats.values().stream()
.sorted((a, b) -> Long.compare(b.getErrorCount(), a.getErrorCount()))
.limit(5)
.collect(Collectors.toList());
}
/**
* 需求3: 每个接口的错误码明细
* @return 接口错误明细列表
*/
public List<InterfaceErrorDetail> getInterfaceErrorDetails() {
// 按接口名称分组
Map<String, List<HttpSample>> samplesByInterface = samples.stream()
.collect(Collectors.groupingBy(HttpSample::getLb));
List<InterfaceErrorDetail> result = new ArrayList<>();
samplesByInterface.forEach((interfaceName, interfaceSamples) -> {
// 过滤出该接口的错误请求
List<HttpSample> errorSamples = interfaceSamples.stream()
.filter(s -> !s.getS())
.collect(Collectors.toList());
// 按错误码统计
Map<String, Long> errorCodeCounts = errorSamples.stream()
.collect(Collectors.groupingBy(
HttpSample::getRc,
Collectors.counting()
));
if (!errorCodeCounts.isEmpty()) {
result.add(new InterfaceErrorDetail(interfaceName, errorCodeCounts));
}
});
return result;
}
// 辅助方法:获取所有接口的错误统计
private Map<String, InterfaceErrorStat> getAllInterfacesErrorStats() {
// 按接口名称分组
Map<String, List<HttpSample>> samplesByInterface = samples.stream()
.collect(Collectors.groupingBy(HttpSample::getLb));
Map<String, InterfaceErrorStat> result = new HashMap<>();
samplesByInterface.forEach((interfaceName, interfaceSamples) -> {
long total = interfaceSamples.size();
long errors = interfaceSamples.stream()
.filter(s -> !s.getS())
.count();
result.put(interfaceName, new InterfaceErrorStat(interfaceName, total, errors));
});
return result;
}
}

View File

@@ -0,0 +1,793 @@
package com.test.common.utils;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import com.test.common.core.domain.model.*;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.config.gui.ArgumentsPanel;
import org.apache.jmeter.control.GenericController;
import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.control.gui.LogicControllerGui;
import org.apache.jmeter.control.gui.LoopControlPanel;
import org.apache.jmeter.control.gui.TestPlanGui;
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.extractor.json.jsonpath.JSONPostProcessor;
import org.apache.jmeter.extractor.json.jsonpath.gui.JSONPostProcessorGui;
import org.apache.jmeter.protocol.http.control.Header;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
import org.apache.jmeter.protocol.http.gui.HeaderPanel;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.reporters.Summariser;
import org.apache.jmeter.samplers.SampleSaveConfiguration;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testbeans.gui.TestBeanGUI;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.testelement.property.*;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jmeter.threads.gui.ThreadGroupGui;
import org.apache.jmeter.timers.ConstantThroughputTimer;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.HashTree;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* @author liangdaliang
* @DescriptionJMeterter线程组工具类
* @date 2025-04-14 17:44
*/
public class JMeterGroupUtil {
private static final Logger logger = LoggerFactory.getLogger(JMeterGroupUtil.class);
/**
* 生成jmeter测试执行计划并获取执行结果
* @param jmeterGroupRequest
* @return
*/
public static JmeterGlobalStatEntity getJmeterResult(JmeterGroupRequest jmeterGroupRequest) {
Long id = jmeterGroupRequest.getTestCaseId();
Integer concurrentThreads = jmeterGroupRequest.getConcurrentThreads();
Integer loopCount = jmeterGroupRequest.getLoopCount();
Integer errorOperType = jmeterGroupRequest.getErrorOperType();
Integer executeType = jmeterGroupRequest.getExecuteType();
Integer rampUpSeconds = jmeterGroupRequest.getRampUpSeconds();
Long pressureSecond = jmeterGroupRequest.getPressureSecond();
Integer rpsStatus = jmeterGroupRequest.getRpsStatus();
Integer rpsLimit = jmeterGroupRequest.getRpsLimit();
String jmeterHomePath = jmeterGroupRequest.getJmeterHomePath();
JmeterGlobalStatEntity result = null;
try {
// 1. 初始化 JMeter
JMeterUtils.loadJMeterProperties(jmeterHomePath + "/bin/jmeter.properties");
JMeterUtils.setJMeterHome(jmeterHomePath);
JMeterUtils.initLocale();
// 2. 创建测试计划
TestPlan testPlan = createTestPlan("Dynamic Test Plan");
// 3. 创建线程组
org.apache.jmeter.threads.ThreadGroup threadGroup = createThreadGroup(concurrentThreads, loopCount, errorOperType, executeType, rampUpSeconds, pressureSecond);
// 4. 获取结果:如汇总报告、查看结果树
String replayLogPath = jmeterHomePath + "/p_replay_result"+ id +".log";
String summaryReportPath = jmeterHomePath + "/p_summary_report"+ id +".log";
List<ResultCollector> resultCollector = getResultCollector(replayLogPath, summaryReportPath);
// 5. 构建测试树新增每个用例下的http请求节点
HashTree firstTreeTestPlan = new HashTree();
HashTree secondHashTree = new HashTree();
HashTree thirdHashTree = new HashTree();
// 6. 获取设置吞吐量
ConstantThroughputTimer constantThroughputTimer = null;
thirdHashTree.add(resultCollector);
if (rpsStatus != null && rpsStatus == 1) {
constantThroughputTimer = getConstantThroughputTimer(rpsLimit);
thirdHashTree.add(constantThroughputTimer);
}
HashTree threadGroupHashTree = secondHashTree.add(threadGroup);
GenericController simpleController = new GenericController();
simpleController.setName("简单顺序逻辑控制器");
simpleController.setProperty(TestElement.TEST_CLASS, GenericController.class.getName());
simpleController.setProperty(TestElement.GUI_CLASS, LogicControllerGui.class.getName());
HashTree simpleControllerTree = threadGroupHashTree.add(simpleController);
dealHttpHashTreeWithRequestList(simpleControllerTree, jmeterGroupRequest.getJmeterRequestList());
secondHashTree.add(threadGroup, thirdHashTree);
firstTreeTestPlan.add(testPlan, secondHashTree);
// 7. 保存测试计划为 JMX 文件
File jmxFile = new File(jmeterHomePath + "/p_dynamic_test_plan"+ id +".jmx");
SaveService.saveTree(firstTreeTestPlan, new FileOutputStream(jmxFile));
// 8. 运行 JMeter 测试
File resultFile = new File(jmeterHomePath + "/p_summary_report"+ id +".log");
if (resultFile.exists()) {
resultFile.delete();
}
StandardJMeterEngine jmeter = new StandardJMeterEngine();
jmeter.configure(firstTreeTestPlan);
jmeter.run();
while (jmeter.isActive()) {
System.out.println("JMeter isActive");
Thread.sleep(1000); // 每隔 1 秒检查一次
}
// 9. 获取响应结果
result = getResultMessageFromFile(jmeterHomePath + "/p_summary_report"+ id +".log");
// if (result != null) {
// result.put("requestHeader", requestHeaderJson);
// result.put("requestBody", requestBody);
// }
System.out.println("JMeter 测试执行完成!");
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 处理线程组下新增每个用例下的http请求节点
* @param thirdHashTree
* @param requestList
*/
private static void dealHttpHashTreeWithRequestList(HashTree thirdHashTree, List<JmeterRequest> requestList) {
for (JmeterRequest jmeterRequest : requestList) {
try {
HashTree fourHashTree = new HashTree();
// 创建 HTTP 请求
String url = jmeterRequest.getUrl();
int port = jmeterRequest.getPort();
String method = jmeterRequest.getMethod().toUpperCase();
String requestBody = jmeterRequest.getRequestBody();
String requestParams = jmeterRequest.getRequestParams();
Map<String, String> requestParamsMap = convertJsonStringToMap(requestParams);
String requestHeader = jmeterRequest.getRequestHeader();
HTTPSamplerProxy httpSampler = null;
if ("POST".equals(method)) {
httpSampler = createPostHttpSampler(
jmeterRequest.getTestCaseName(),
url, // 请求地址
port,
requestBody, // 请求体
requestParamsMap // 查询参数
);
} else {
httpSampler = createGetHttpSampler(
jmeterRequest.getTestCaseName(),
url, // 请求地址
port,
requestParamsMap // 查询参数
);
}
// 创建请求头管理器
Map<String, String> headerMap = new HashMap<>();
if (!StringUtils.isEmpty(requestHeader) && !requestHeader.equals("[]")) {
Gson gson = new Gson();
// 定义类型
Type type = new TypeToken<List<Map<String, String>>>() {
}.getType();
// 解析 JSON 数组
List<Map<String, String>> headerList = null;
try {
headerList = gson.fromJson(requestHeader, type);
// 将 List<Map<String, String>> 转换为 Map<String, String>
for (Map<String, String> entry : headerList) {
String key = entry.get("key");
String value = entry.get("value");
headerMap.put(key, value);
}
} catch (Exception e) {
logger.error("requestHeader gson.fromJson异常requestHeader" + requestHeader, e);
}
}
HeaderManager headerManager = createHeaderManager(headerMap);
List<String> extractionRuleList = jmeterRequest.getExtractionRuleList();
if (headerManager != null) {
fourHashTree.add(headerManager);
createJsonPostProcessor(extractionRuleList, fourHashTree);
thirdHashTree.add(httpSampler, fourHashTree);
} else {
createJsonPostProcessor(extractionRuleList, fourHashTree);
if (fourHashTree.isEmpty()) {
thirdHashTree.add(httpSampler);
} else {
thirdHashTree.add(httpSampler, fourHashTree);
}
}
} catch (Exception e) {
String info = "url:" + jmeterRequest.getUrl() + ", port:" + jmeterRequest.getPort();
logger.error(info + " dealHttpHashTreeWithRequest异常", e);
}
}
}
/**
* 创建Json参数提取
* @param extractionRuleList
* @param fourHashTree
* @return
*/
private static void createJsonPostProcessor(List<String> extractionRuleList, HashTree fourHashTree) {
if (extractionRuleList != null) {
for (String extractionRule : extractionRuleList) {
String[] array = extractionRule.split(",");
JSONPostProcessor jsonExtractor = new JSONPostProcessor();
jsonExtractor.setName("提取" + array[0]);
jsonExtractor.setProperty(TestElement.TEST_CLASS, JSONPostProcessor.class.getName());
jsonExtractor.setProperty(TestElement.GUI_CLASS, JSONPostProcessorGui.class.getName());
jsonExtractor.setEnabled(true);
if (array[1].startsWith("$")) {
jsonExtractor.setJsonPathExpressions(array[1]); // JSONPath 表达式
} else {
jsonExtractor.setJsonPathExpressions("$." + array[1]); // JSONPath 表达式
}
jsonExtractor.setMatchNumbers("1"); // 0表示随机1表示第一个
jsonExtractor.setRefNames(array[0]); // 存储变量名
jsonExtractor.setDefaultValues("");
fourHashTree.add(jsonExtractor);
}
}
}
/**
* 创建测试计划
* @param name
* @return
*/
private static TestPlan createTestPlan(String name) {
TestPlan testPlan = new TestPlan(name);
testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName());
testPlan.setProperty(TestElement.GUI_CLASS, TestPlanGui.class.getName());
testPlan.setUserDefinedVariables((Arguments) new ArgumentsPanel().createTestElement());
return testPlan;
}
/**
* 创建线程组
* @param numThreads
* @param loops
* @param errorOperType
* @param executeType
* @param rampUpSeconds
* @param pressureSecond
* @return
*/
private static org.apache.jmeter.threads.ThreadGroup createThreadGroup(Integer numThreads, Integer loops, Integer errorOperType, Integer executeType, Integer rampUpSeconds, Long pressureSecond) {
org.apache.jmeter.threads.ThreadGroup threadGroup = new org.apache.jmeter.threads.ThreadGroup();
threadGroup.setName("Thread Group");
threadGroup.setNumThreads(numThreads);
threadGroup.setRampUp(rampUpSeconds);
threadGroup.setDelay(0);
if (executeType == 1) {
threadGroup.setDuration(pressureSecond);
threadGroup.setProperty(new TestElementProperty(ThreadGroup.MAIN_CONTROLLER, createLoopController(-1)));
threadGroup.setProperty(new BooleanProperty(ThreadGroup.IS_SAME_USER_ON_NEXT_ITERATION, true));
threadGroup.setScheduler(true);
} else {
threadGroup.setScheduler(false);
threadGroup.setProperty(new TestElementProperty(ThreadGroup.MAIN_CONTROLLER, createLoopController(loops)));
}
if (errorOperType == 1) {
threadGroup.setProperty(new StringProperty(ThreadGroup.ON_SAMPLE_ERROR, "continue"));
} else if (errorOperType == 2) {
threadGroup.setProperty(new StringProperty(ThreadGroup.ON_SAMPLE_ERROR, "startnextloop"));
} else if (errorOperType == 3) {
threadGroup.setProperty(new StringProperty(ThreadGroup.ON_SAMPLE_ERROR, "stopthread"));
} else if (errorOperType == 4) {
threadGroup.setProperty(new StringProperty(ThreadGroup.ON_SAMPLE_ERROR, "stoptest"));
} else if (errorOperType == 5) {
threadGroup.setProperty(new StringProperty(ThreadGroup.ON_SAMPLE_ERROR, "stoptestnow"));
}
threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
threadGroup.setProperty(TestElement.GUI_CLASS, ThreadGroupGui.class.getName());
threadGroup.setProperty(new BooleanProperty(TestElement.ENABLED, true));
return threadGroup;
}
/**
* 创建轮询控制器
* @return
*/
private static LoopController createLoopController(Integer loops) {
LoopController loopController = new LoopController();
loopController.setContinueForever(false);
loopController.setProperty(new StringProperty(TestElement.GUI_CLASS, LoopControlPanel.class.getName()));
loopController.setProperty(new StringProperty(TestElement.TEST_CLASS, LoopController.class.getName()));
loopController.setProperty(new StringProperty(TestElement.NAME, "循环控制器"));
loopController.setProperty(new BooleanProperty(TestElement.ENABLED, true));
if (loops == 0) {
loops = 1;
}
loopController.setProperty(new IntegerProperty(LoopController.LOOPS, loops));
return loopController;
}
/**
* 创建get请求方式
* @param testCaseName
* @param urlString
* @param port
* @param requestParams
* @return
* @throws MalformedURLException
*/
private static HTTPSamplerProxy createGetHttpSampler(String testCaseName, String urlString, int port, Map<String, String> requestParams) throws MalformedURLException {
URL url = new URL(urlString);
// 提取域名(不包括端口号)
String domain = url.getHost();
// 提取路径(不包括查询参数和片段标识符)
String path = url.getPath();
HTTPSamplerProxy httpSampler = new HTTPSamplerProxy();
httpSampler.setName(testCaseName);
httpSampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
httpSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
httpSampler.setDomain(domain); // 提取域名
if (requestParams != null) {
path += "?";
path += mapToQueryString(requestParams);
}
httpSampler.setPath(path); // 提取路径
httpSampler.setPort(port);
httpSampler.setMethod("GET");
httpSampler.setConnectTimeout("5000");
httpSampler.setUseKeepAlive(true);
return httpSampler;
}
/**
* 构建get请求查询参数
* @param params
* @return
*/
public static String mapToQueryString(Map<String, String> params) {
StringBuilder queryString = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
if (!queryString.isEmpty()) {
queryString.append("&");
}
// 对键和值进行 URL 编码
String encodedKey = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8);
String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8);
queryString.append(encodedKey).append("=").append(encodedValue);
}
return queryString.toString();
}
/**
* 转换[{"key":"authorization","value":"tttt"},{"key":"name","value":"123"}]为Map结构
* @param jsonString
* @return
*/
private static Map<String, String> convertJsonStringToMap(String jsonString) {
if (StringUtils.isEmpty(jsonString) || jsonString.equals("[]")) {
return null;
}
Gson gson = new Gson();
// 定义类型用于告诉Gson我们期望的结果类型是一个包含键值对的对象列表
Type listType = new TypeToken<List<Map<String, String>>>(){}.getType();
// 将JSON字符串转换为List<Map<String, String>>
List<Map<String, String>> keyValuePairs = null;
try {
// jsonString = jsonString.replaceAll(", \\[\\{\\}]", "");
// jsonString = jsonString.replaceAll(",\\[\\{\\}]", "");
keyValuePairs = gson.fromJson(jsonString, listType);
} catch (Exception e) {
logger.error("gson.fromJson发生异常jsonString" + jsonString, e);
return null;
}
// 创建一个新的Map<String, String>用于存储结果
Map<String, String> resultMap = new HashMap<>();
for (Map<String, String> pair : keyValuePairs) {
// 确保每个map都有"key"和"value"两个字段
if (pair.containsKey("key") && pair.containsKey("value")) {
resultMap.put(pair.get("key"), pair.get("value"));
}
}
return resultMap;
}
/**
* 创建post请求方式
* @param testCaseName
* @param urlString
* @param port
* @param requestBody
* @param requestParams
* @return
* @throws MalformedURLException
*/
private static HTTPSamplerProxy createPostHttpSampler(String testCaseName, String urlString, int port, String requestBody, Map<String, String> requestParams) throws MalformedURLException {
URL url = new URL(urlString);
// 提取域名(不包括端口号)
String domain = url.getHost();
// 提取路径(不包括查询参数和片段标识符)
String path = url.getPath();
// int portTest = url.getPort();
HTTPSamplerProxy httpSampler = new HTTPSamplerProxy();
httpSampler.setName(testCaseName);
httpSampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
httpSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
httpSampler.setDomain(domain);
if (requestParams != null) {
path += "?";
path += mapToQueryString(requestParams);
}
httpSampler.setPath(path);
httpSampler.setPort(port);
httpSampler.setMethod("POST");
httpSampler.setConnectTimeout("5000");
httpSampler.setUseKeepAlive(true);
// 设置请求体
httpSampler.setPostBodyRaw(true); // 使用原始请求体
httpSampler.addNonEncodedArgument("", requestBody, "");
return httpSampler;
}
/**
* 创建http请求头管理器
* @param headerMap
* @return
*/
private static HeaderManager createHeaderManager(Map<String, String> headerMap) {
if (headerMap == null || headerMap.isEmpty()) {
return null;
}
HeaderManager headerManager = new HeaderManager();
headerManager.setName("HTTP Header Manager");
headerManager.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
headerManager.setProperty(TestElement.GUI_CLASS, HeaderPanel.class.getName());
// 添加默认 Content-Type 请求头
// if (!headerMap.containsKey("Content-Type")) {
// Header contentTypeHeader = new Header();
// contentTypeHeader.setName("Content-Type");
// contentTypeHeader.setValue("application/json; charset=UTF-8");
// headerManager.add(contentTypeHeader);
// }
// 遍历 headerMap动态添加请求头
for (Map.Entry<String, String> entry : headerMap.entrySet()) {
Header header = new Header();
header.setName(entry.getKey()); // 请求头名称
header.setValue(entry.getValue()); // 请求头值
headerManager.add(header);
}
return headerManager;
}
/***
* 监听结果树
* @param replayLogPath 将结果保存到文件中,这个是文件的路径
* @param summaryReportPath 将汇总报告保存到文件中,这个是文件的路径
* @return
*/
private static List<ResultCollector> getResultCollector(String replayLogPath, String summaryReportPath) {
// 察看结果数
List<ResultCollector> resultCollectors = new ArrayList<>();
// Summariser summariser = new Summariser("速度");
// ResultCollector resultCollector = new ResultCollector(summariser);
// resultCollector.setProperty(new BooleanProperty("ResultCollector.error_logging", false));
// resultCollector.setProperty(new ObjectProperty("saveConfig", getSampleSaveConfig()));
// resultCollector.setProperty(new StringProperty("TestElement.gui_class", "org.apache.jmeter.visualizers.ViewResultsFullVisualizer"));
// resultCollector.setProperty(new StringProperty("TestElement.name", "察看结果树"));
// resultCollector.setProperty(new StringProperty("TestElement.enabled", "true"));
// resultCollector.setProperty(new StringProperty("filename", replayLogPath));
// resultCollectors.add(resultCollector);
// 结果汇总
Summariser summariser = new Summariser("汇总报告");
ResultCollector resultTotalCollector = new ResultCollector(summariser);
resultTotalCollector.setProperty(new BooleanProperty("ResultCollector.error_logging", false));
resultTotalCollector.setProperty(new ObjectProperty("saveConfig", getSampleSaveConfig()));
resultTotalCollector.setProperty(new StringProperty("TestElement.gui_class", "org.apache.jmeter.visualizers.SummaryReport"));
resultTotalCollector.setProperty(new StringProperty("TestElement.name", "汇总报告"));
resultTotalCollector.setProperty(new StringProperty("TestElement.enabled", "true"));
resultTotalCollector.setProperty(new StringProperty("filename", summaryReportPath));
resultCollectors.add(resultTotalCollector);
return resultCollectors;
}
/**
* 配置采样结果信息
* @return
*/
private static SampleSaveConfiguration getSampleSaveConfig() {
SampleSaveConfiguration sampleSaveConfiguration = new SampleSaveConfiguration();
sampleSaveConfiguration.setTime(true);
sampleSaveConfiguration.setLatency(true);
sampleSaveConfiguration.setTimestamp(true);
sampleSaveConfiguration.setSuccess(true);
sampleSaveConfiguration.setLabel(true);
sampleSaveConfiguration.setCode(true);
sampleSaveConfiguration.setMessage(true);
sampleSaveConfiguration.setThreadName(true);
sampleSaveConfiguration.setDataType(true);
sampleSaveConfiguration.setEncoding(true);
sampleSaveConfiguration.setAssertions(true);
sampleSaveConfiguration.setSubresults(true);
sampleSaveConfiguration.setResponseData(false);
sampleSaveConfiguration.setSamplerData(true);
sampleSaveConfiguration.setAsXml(true);
sampleSaveConfiguration.setFieldNames(true);
sampleSaveConfiguration.setResponseHeaders(false);
sampleSaveConfiguration.setRequestHeaders(false);
sampleSaveConfiguration.setAssertionResultsFailureMessage(true);
//sampleSaveConfiguration.setsserAtionsResultsToSave(0); assertionsResultsToSave
sampleSaveConfiguration.setBytes(true);
sampleSaveConfiguration.setSentBytes(true);
sampleSaveConfiguration.setUrl(true);
sampleSaveConfiguration.setThreadCounts(true);
sampleSaveConfiguration.setIdleTime(true);
sampleSaveConfiguration.setConnectTime(true);
return sampleSaveConfiguration;
}
/***
* 限制QPS设置
* @param throughputTimer
* @return
*/
private static ConstantThroughputTimer getConstantThroughputTimer(int throughputTimer) {
ConstantThroughputTimer constantThroughputTimer = new ConstantThroughputTimer();
constantThroughputTimer.setEnabled(true);
constantThroughputTimer.setName("常数吞吐量定时器");
constantThroughputTimer.setProperty(TestElement.TEST_CLASS, ConstantThroughputTimer.class.getName());
constantThroughputTimer.setProperty(TestElement.GUI_CLASS, TestBeanGUI.class.getName());
constantThroughputTimer.setCalcMode(ConstantThroughputTimer.Mode.AllActiveThreads.ordinal());
constantThroughputTimer.setProperty(new IntegerProperty("calcMode", ConstantThroughputTimer.Mode.AllActiveThreads.ordinal()));
DoubleProperty doubleProperty = new DoubleProperty();
doubleProperty.setName("throughput");
doubleProperty.setValue(throughputTimer * 60f);
constantThroughputTimer.setProperty(doubleProperty);
return constantThroughputTimer;
}
/**
* 从结果文件读取响应内容
* @param filePath
* @return
*/
private static JmeterGlobalStatEntity getResultMessageFromFile(String filePath) {
File file = new File(filePath);
if (!file.exists()) {
return null;
}
List<LabelStatsEntity> statsEntityList = new ArrayList<>();
try {
// 1. 创建DocumentBuilderFactory对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 2. 创建DocumentBuilder对象
DocumentBuilder builder = factory.newDocumentBuilder();
// 3. 解析XML文件获取Document对象
Document document = builder.parse(new File(filePath));
// 4. 获取所有<httpSample>节点
NodeList httpSampleList = document.getElementsByTagName("httpSample");
// 初始化统计变量
Map<String, LabelStats> labelStatsMap = new LinkedHashMap<>();
List<HttpSample> samples = new ArrayList<>();
// long startTime = Long.MAX_VALUE;
// long endTime = Long.MIN_VALUE;
long totalRequests = 0;
long failedRequests = 0;
long totalResponseTime = 0;
long totalMinResponseTime = Long.MAX_VALUE;
long totalMaxResponseTime = Long.MIN_VALUE;
long totalTimeMillis = 0;
for (int i = 0; i < httpSampleList.getLength(); i++) {
Node httpSampleNode = httpSampleList.item(i);
if (httpSampleNode.getNodeType() == Node.ELEMENT_NODE) {
Element httpSampleElement = (Element) httpSampleNode;
// 提取字段
String label = httpSampleElement.getAttribute("lb");
boolean success = Boolean.parseBoolean(httpSampleElement.getAttribute("s"));
long responseTime = Long.parseLong(httpSampleElement.getAttribute("t"));
long lt = Long.parseLong(httpSampleElement.getAttribute("lt"));
long ct = Long.parseLong(httpSampleElement.getAttribute("ct"));
totalTimeMillis += responseTime + lt + ct;
// long timestamp = Long.parseLong(httpSampleElement.getAttribute("ts"));
long receivedBytes = Long.parseLong(httpSampleElement.getAttribute("by"));
long sentBytes = Long.parseLong(httpSampleElement.getAttribute("sby"));
String responseCode = httpSampleElement.getAttribute("rc");
samples.add(new HttpSample(label, success, responseCode));
// 更新全局统计
totalRequests++;
totalResponseTime += responseTime;
totalMinResponseTime = Math.min(totalMinResponseTime, responseTime);
totalMaxResponseTime = Math.max(totalMaxResponseTime, responseTime);
if (!success) {
failedRequests++;
}
// startTime = Math.min(startTime, timestamp);
// endTime = Math.max(endTime, timestamp);
// 更新按标签的统计
LabelStats stats = labelStatsMap.getOrDefault(label, new LabelStats());
stats.totalRequests++;
stats.totalResponseTime += responseTime;
stats.minResponseTime = Math.min(stats.minResponseTime, responseTime);
stats.maxResponseTime = Math.max(stats.maxResponseTime, responseTime);
stats.receivedBytes += receivedBytes;
stats.sentBytes += sentBytes;
if (!success) {
stats.failedRequests++;
}
labelStatsMap.put(label, stats);
}
}
// 计算总时长(秒)
double totalTimeInSeconds = totalTimeMillis / 1000.0;
// double totalTimeInSeconds2 = (endTime - startTime) / 1000.0;
// 输出汇总报告
for (Map.Entry<String, LabelStats> entry : labelStatsMap.entrySet()) {
String label = entry.getKey();
LabelStats stats = entry.getValue();
// 计算指标
long average = stats.totalResponseTime / stats.totalRequests;
double errorRate = (stats.failedRequests / (double) stats.totalRequests) * 100;
double throughput = stats.totalRequests / totalTimeInSeconds;
double receivedKBPerSec = (stats.receivedBytes / 1024.0) / totalTimeInSeconds;
double sentKBPerSec = (stats.sentBytes / 1024.0) / totalTimeInSeconds;
LabelStatsEntity labelStatsEntity = new LabelStatsEntity();
labelStatsEntity.setLabel(label);
labelStatsEntity.setSamples(stats.totalRequests);
labelStatsEntity.setAverage(average);
labelStatsEntity.setMin(stats.minResponseTime);
labelStatsEntity.setMax(stats.maxResponseTime);
labelStatsEntity.setErrorRate(errorRate);
labelStatsEntity.setThroughput(throughput);
labelStatsEntity.setReceivedKBPerSec(receivedKBPerSec);
labelStatsEntity.setSentKBPerSec(sentKBPerSec);
statsEntityList.add(labelStatsEntity);
}
// 输出全局汇总
long globalResponseAverage = totalResponseTime / totalRequests;
double globalErrorRate = (failedRequests / (double) totalRequests) * 100;
double globalThroughput = totalRequests / totalTimeInSeconds;
double globalReceivedKBPerSec = labelStatsMap.values().stream()
.mapToLong(stats -> stats.receivedBytes)
.sum() / 1024.0 / totalTimeInSeconds;
double globalSentKBPerSec = labelStatsMap.values().stream()
.mapToLong(stats -> stats.sentBytes)
.sum() / 1024.0 / totalTimeInSeconds;
LabelStatsEntity labelStatsEntity = new LabelStatsEntity();
labelStatsEntity.setLabel("TOTAL");
labelStatsEntity.setSamples(totalRequests);
labelStatsEntity.setAverage(globalResponseAverage);
labelStatsEntity.setMin(totalMinResponseTime);
labelStatsEntity.setMax(totalMaxResponseTime);
labelStatsEntity.setErrorRate(globalErrorRate);
labelStatsEntity.setThroughput(globalThroughput);
labelStatsEntity.setReceivedKBPerSec(globalReceivedKBPerSec);
labelStatsEntity.setSentKBPerSec(globalSentKBPerSec);
statsEntityList.add(labelStatsEntity);
// 错误报告汇总
HttpSampleAnalyzer analyzer = new HttpSampleAnalyzer(samples);
List<ErrorCodeStat> errorCodeStatList = analyzer.analyzeErrorCodes();
List<InterfaceErrorStat> top5InterfaceErrorStatList = analyzer.getTop5ErrorInterfaces();
List<InterfaceErrorDetail> interfaceErrorDetailList = analyzer.getInterfaceErrorDetails();
ErrorTotalStats errorTotalStats = new ErrorTotalStats();
errorTotalStats.setErrorCodeStatList(errorCodeStatList);
errorTotalStats.setTop5InterfaceErrorStatList(top5InterfaceErrorStatList);
errorTotalStats.setInterfaceErrorDetailList(interfaceErrorDetailList);
JmeterGlobalStatEntity globalStatEntity = new JmeterGlobalStatEntity();
globalStatEntity.setStatsEntityList(statsEntityList);
globalStatEntity.setErrorTotalStats(errorTotalStats);
return globalStatEntity;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
static class LabelStats {
long totalRequests = 0;
long totalResponseTime = 0;
long minResponseTime = Long.MAX_VALUE;
long maxResponseTime = Long.MIN_VALUE;
int failedRequests = 0;
long receivedBytes = 0;
long sentBytes = 0;
}
/**
* 从响应头中读取Map信息结构
* @param responseHeader
* @return
*/
public static Map<String, String> parseHeaders(String responseHeader) {
Map<String, String> headerMap = new HashMap<>();
if (responseHeader == null) {
return headerMap;
}
// 按行拆分
String[] lines = responseHeader.split("\n");
// 遍历每一行
for (String line : lines) {
// 忽略空行和 HTTP 状态行
if (line.trim().isEmpty() || line.startsWith("HTTP/")) {
continue;
}
// 按冒号拆分键值对
int colonIndex = line.indexOf(":");
if (colonIndex > 0) {
String key = line.substring(0, colonIndex).trim();
String value = line.substring(colonIndex + 1).trim();
headerMap.put(key, value);
}
}
return headerMap;
}
/**
* 根据 JSONPath 表达式从 JSON 中提取字段值
*
* @param json JSON 字符串
* @param expression JSONPath 表达式
* @return 字段值,如果字段不存在则返回 null
*/
public static String extractFieldValue(String json, String expression) {
try {
Object result = JsonPath.read(json, expression);
return result != null ? result.toString() : null;
} catch (PathNotFoundException e) {
// 如果字段不存在,返回 null
return null;
}
}
public static void main(String[] args) {
// String s = "[{\"key\":\"authorization\",\"value\":\"Bearer eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjhkZTZlMWYzLTU0YjMtNGM5MC05YTczLTA0NDkxYmE2NTZlNiJ9.oepUXspCPm6Gjjz3pXbs4O87p3ByemxxhRh5HXUFGK2x-lDb2uxdSRfITiE9LeDYQQNTD6UPYKPda2PWLyAUoA\"},[{\"key\":\"\",\"value\":\"\"}]]";
// s = s.replaceAll(",\\s*\\[\\{\"key\":\"\",\"value\":\"\"\\}]", "");
// Gson gson = new Gson();
// // 定义类型
// Type type = new TypeToken<List<Map<String, String>>>() {}.getType();
// gson.fromJson(s, type);
String paramJson = "{\"md5Value\":\"value1\",\"fileName\":\"value2\"}";
paramJson = "{\"name\":\"John\",\"city\":\"New York\",\"age\":30}";
String requestHeader = "{\"Content-Type\":\"application/json; charset=UTF-8\",\"Authorization\":\"Bearer token123\"}";
String jmeterHomePath = "D:/apache-jmeter-5.4.3";
// String result = getJmeterResult("http://127.0.0.1:3000/api/items/add", 3000, "POST", paramJson, requestHeader, jmeterHomePath);
// getJmeterResult(123L, "http://127.0.0.1:3000/api/items/user", 3000, "GET", paramJson, requestHeader, jmeterHomePath);
// System.out.println(result);
}
}

View File

@@ -5,6 +5,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author liangdaliang
@@ -66,6 +68,32 @@ public class MySQLExecutor {
return result;
}
public static String replaceSqlVariables(String sql, Map<String, String> params) {
if (sql == null || params == null) {
return sql;
}
// 正则匹配 ${variable_name}
Pattern pattern = Pattern.compile("\\$\\{([^}]*)\\}");
Matcher matcher = pattern.matcher(sql);
StringBuilder sb = new StringBuilder();
while (matcher.find()) {
String key = matcher.group(1).trim(); // 获取变量名
String replacement = params.get(key); // 从 map 中获取对应值
if (replacement != null) {
// 如果值存在,替换并加上单引号(适用于字符串)
// 如果你需要支持数字不加引号,请自行判断类型
replacement = "'" + replacement.replace("'", "''") + "'";
matcher.appendReplacement(sb, replacement);
}
}
matcher.appendTail(sb);
return sb.toString();
}
// public static void main(String[] args) {
// String url = "jdbc:mysql://47.103.142.5:3306/cmcf-test";
// List<String> columnNameList = new ArrayList<>();

View File

@@ -0,0 +1,953 @@
package com.test.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.io.File;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
* Selenium 工具类
*/
@Slf4j
public class SeleniumUtils {
private WebDriver driver;
private WebDriverWait wait;
private Actions actions;
// 构造函数
public SeleniumUtils(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
this.actions = new Actions(driver);
}
// 设置显式等待超时时间
public void setWaitTimeout(long seconds) {
this.wait = new WebDriverWait(driver, Duration.ofSeconds(seconds));
}
// 打开URL
public void openUrl(String url) {
driver.get(url);
}
// 获取当前URL
public String getCurrentUrl() {
return driver.getCurrentUrl();
}
// 获取页面标题
public String getPageTitle() {
return driver.getTitle();
}
// 通过ID查找元素
public WebElement findElementById(String id) {
return wait.until(ExpectedConditions.presenceOfElementLocated(By.id(id)));
}
// 通过name查找元素
public WebElement findElementByName(String name) {
return wait.until(ExpectedConditions.presenceOfElementLocated(By.name(name)));
}
// 通过className查找元素
public WebElement findElementByClassName(String className) {
return wait.until(ExpectedConditions.presenceOfElementLocated(By.className(className)));
}
// 通过xpath查找元素
public WebElement findElementByXpath(String xpath) {
return wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(xpath)));
}
// 通过cssSelector查找元素
public WebElement findElementByCssSelector(String cssSelector) {
return wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(cssSelector)));
}
// 通过linkText查找元素
public WebElement findElementByLinkText(String linkText) {
return wait.until(ExpectedConditions.presenceOfElementLocated(By.linkText(linkText)));
}
// 通过partialLinkText查找元素
public WebElement findElementByPartialLinkText(String partialLinkText) {
return wait.until(ExpectedConditions.presenceOfElementLocated(By.partialLinkText(partialLinkText)));
}
// 通过tagName查找元素
public WebElement findElementByTagName(String tagName) {
return wait.until(ExpectedConditions.presenceOfElementLocated(By.tagName(tagName)));
}
// 查找多个元素
public List<WebElement> findElements(By by) {
return wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(by));
}
// 输入文本
public void sendKeys(WebElement element, String text) {
wait.until(ExpectedConditions.visibilityOf(element)).clear();
element.sendKeys(text);
}
// 点击元素
public void click(WebElement element) {
wait.until(ExpectedConditions.elementToBeClickable(element)).click();
}
// 获取元素文本
public String getText(WebElement element) {
return wait.until(ExpectedConditions.visibilityOf(element)).getText();
}
// 获取元素属性值
public String getAttribute(WebElement element, String attribute) {
return wait.until(ExpectedConditions.visibilityOf(element)).getAttribute(attribute);
}
// 判断元素是否显示
public boolean isDisplayed(WebElement element) {
try {
return element.isDisplayed();
} catch (NoSuchElementException e) {
return false;
}
}
// 判断元素是否启用
public boolean isEnabled(WebElement element) {
try {
return element.isEnabled();
} catch (NoSuchElementException e) {
return false;
}
}
// 判断元素是否被选中
public boolean isSelected(WebElement element) {
try {
return element.isSelected();
} catch (NoSuchElementException e) {
return false;
}
}
// 选择下拉框选项(通过value)
public void selectByValue(WebElement element, String value) {
new Select(wait.until(ExpectedConditions.visibilityOf(element))).selectByValue(value);
}
// 选择下拉框选项(通过visible text)
public void selectByVisibleText(WebElement element, String text) {
new Select(wait.until(ExpectedConditions.visibilityOf(element))).selectByVisibleText(text);
}
// 选择下拉框选项(通过index)
public void selectByIndex(WebElement element, int index) {
new Select(wait.until(ExpectedConditions.visibilityOf(element))).selectByIndex(index);
}
// 获取下拉框所有选项
public List<WebElement> getSelectOptions(WebElement element) {
return new Select(element).getOptions();
}
// 获取选中的下拉框选项
public WebElement getFirstSelectedOption(WebElement element) {
return new Select(element).getFirstSelectedOption();
}
// 鼠标悬停
public void mouseHover(WebElement element) {
actions.moveToElement(wait.until(ExpectedConditions.visibilityOf(element))).perform();
}
// 鼠标双击
public void doubleClick(WebElement element) {
actions.doubleClick(wait.until(ExpectedConditions.visibilityOf(element))).perform();
}
// 鼠标右键点击
public void contextClick(WebElement element) {
actions.contextClick(wait.until(ExpectedConditions.visibilityOf(element))).perform();
}
// 拖拽元素
public void dragAndDrop(WebElement source, WebElement target) {
actions.dragAndDrop(
wait.until(ExpectedConditions.visibilityOf(source)),
wait.until(ExpectedConditions.visibilityOf(target))
).perform();
}
// 执行JavaScript
public Object executeScript(String script, Object... args) {
JavascriptExecutor js = (JavascriptExecutor) driver;
return js.executeScript(script, args);
}
// 滚动到元素可见
public void scrollToElement(WebElement element) {
executeScript("arguments[0].scrollIntoView(true);", element);
}
// 滚动到页面底部
public void scrollToBottom() {
executeScript("window.scrollTo(0, document.body.scrollHeight)");
}
// 滚动到页面顶部
public void scrollToTop() {
executeScript("window.scrollTo(0, 0)");
}
// 切换到frame
public void switchToFrame(WebElement frameElement) {
driver.switchTo().frame(frameElement);
}
// 切换到主窗口
public void switchToDefaultContent() {
driver.switchTo().defaultContent();
}
// 切换到父frame
public void switchToParentFrame() {
driver.switchTo().parentFrame();
}
// 切换到alert
public Alert switchToAlert() {
return wait.until(ExpectedConditions.alertIsPresent());
}
// 接受alert
public void acceptAlert() {
switchToAlert().accept();
}
// 取消alert
public void dismissAlert() {
switchToAlert().dismiss();
}
// 获取alert文本
// public String getAlertText() {
// return switchToAlert().getText();
// }
// 在alert中输入文本
public void sendKeysToAlert(String text) {
switchToAlert().sendKeys(text);
}
// 切换到窗口
public void switchToWindow(String windowHandle) {
driver.switchTo().window(windowHandle);
}
// 获取当前窗口句柄
public String getCurrentWindowHandle() {
return driver.getWindowHandle();
}
// 获取所有窗口句柄
public Set<String> getAllWindowHandles() {
return driver.getWindowHandles();
}
// 关闭当前窗口
public void closeCurrentWindow() {
driver.close();
}
// 刷新页面
public void refreshPage() {
driver.navigate().refresh();
}
// 前进
public void navigateForward() {
driver.navigate().forward();
}
// 后退
public void navigateBack() {
driver.navigate().back();
}
// 获取页面源码
public String getPageSource() {
return driver.getPageSource();
}
// 设置窗口大小
public void setWindowSize(int width, int height) {
driver.manage().window().setSize(new Dimension(width, height));
}
// 最大化窗口
public void maximizeWindow() {
driver.manage().window().maximize();
}
// 全屏窗口
public void fullscreenWindow() {
driver.manage().window().fullscreen();
}
// 获取cookie
public Set<Cookie> getCookies() {
return driver.manage().getCookies();
}
// 获取指定cookie
public Cookie getCookieNamed(String name) {
return driver.manage().getCookieNamed(name);
}
// 添加cookie
public void addCookie(Cookie cookie) {
driver.manage().addCookie(cookie);
}
// 删除cookie
public void deleteCookie(Cookie cookie) {
driver.manage().deleteCookie(cookie);
}
// 删除指定cookie
public void deleteCookieNamed(String name) {
driver.manage().deleteCookieNamed(name);
}
// 删除所有cookie
public void deleteAllCookies() {
driver.manage().deleteAllCookies();
}
// 等待元素可见
public void waitForElementVisible(By by, long timeoutInSeconds) {
new WebDriverWait(driver, Duration.ofSeconds(timeoutInSeconds))
.until(ExpectedConditions.visibilityOfElementLocated(by));
}
// 等待元素可点击
public void waitForElementClickable(By by, long timeoutInSeconds) {
new WebDriverWait(driver, Duration.ofSeconds(timeoutInSeconds))
.until(ExpectedConditions.elementToBeClickable(by));
}
// 等待元素消失
public void waitForElementInvisible(By by, long timeoutInSeconds) {
new WebDriverWait(driver, Duration.ofSeconds(timeoutInSeconds))
.until(ExpectedConditions.invisibilityOfElementLocated(by));
}
// 等待文本出现在元素中
public void waitForTextPresentInElement(By by, String text, long timeoutInSeconds) {
new WebDriverWait(driver, Duration.ofSeconds(timeoutInSeconds))
.until(ExpectedConditions.textToBePresentInElementLocated(by, text));
}
// 截屏并保存为Base64
public String takeScreenshotAsBase64() {
return ((TakesScreenshot) driver).getScreenshotAs(OutputType.BASE64);
}
// 截屏并保存为字节数组
public byte[] takeScreenshotAsBytes() {
return ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
}
/**
* 截屏并保存为文件
* @param filePath 保存路径的基础目录
* @return 保存后的文件完整路径
*/
public String takeScreenshotAsFile(String filePath) {
try {
// 生成文件名: screenshot_年月日_时分秒.png
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fileName = "screenshot_" + timestamp + ".png";
// 确保目录存在
File directory = new File(filePath);
if (!directory.exists()) {
boolean created = directory.mkdirs();
if (!created) {
log.error("无法创建目录: {}", filePath);
return null;
}
}
// 检查目录是否可写
if (!directory.canWrite()) {
log.error("目录不可写: {}", filePath);
return null;
}
// 获取截图临时文件
File tempFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
// 构建目标文件路径
String fullPath = filePath + File.separator + fileName;
File targetFile = new File(fullPath);
// 复制文件到目标路径
FileUtils.copyFile(tempFile, targetFile);
log.info("截图已保存到: {}", targetFile.getAbsolutePath());
return targetFile.getAbsolutePath();
} catch (Exception e) {
log.error("截图保存失败: {}", e.getMessage());
return null;
}
}
// 关闭浏览器
public void quit() {
if (driver != null) {
driver.quit();
}
}
//Add SeleniumUtils -----
/**
* 根据句柄ID切换到指定窗口
* @param handleId 窗口句柄ID
*/
public void switchToWindowByHandle(String handleId) {
driver.switchTo().window(handleId);
log.info("已切换到句柄ID为 {} 的窗口", handleId);
}
/**
* 根据网页索引号切换到指定窗口
* @param index 窗口索引从0开始
*/
public void switchToWindowByIndex(int index) {
Set<String> handles = driver.getWindowHandles();
if (index >= 0 && index < handles.size()) {
String handle = handles.toArray(new String[0])[index];
driver.switchTo().window(handle);
log.info("已切换到索引为 {} 的窗口", index);
} else {
throw new NoSuchWindowException("无效的窗口索引: " + index);
}
}
/**
* 切换到初始窗口(第一个打开的窗口)
*/
public void switchToDefaultWindow() {
Set<String> handles = driver.getWindowHandles();
if (!handles.isEmpty()) {
String firstHandle = handles.iterator().next();
driver.switchTo().window(firstHandle);
log.info("已切换回初始窗口");
}
}
/**
* 根据索引切换到指定frame
* @param index frame索引(从0开始)
*/
public void switchToFrameByIndex(int index) {
try {
driver.switchTo().frame(index);
log.info("已切换到索引为 {} 的frame", index);
} catch (NoSuchFrameException e) {
log.error("按索引切换frame失败: {}", e.getMessage());
throw new RuntimeException("找不到索引为 " + index + " 的frame", e);
}
}
/**
* 根据定位方式切换到frame
* @param locatorType 定位类型(id/name/xpath/css等)
* @param locatorValue 定位值
*/
public void switchToFrameByLocator(String locatorType, String locatorValue) {
By locator = getLocator(locatorType, locatorValue);
try {
WebElement frameElement = wait.until(ExpectedConditions.presenceOfElementLocated(locator));
driver.switchTo().frame(frameElement);
log.info("已切换到 {} = '{}' 的frame", locatorType, locatorValue);
} catch (TimeoutException e) {
log.error("等待frame元素超时: {} = '{}'", locatorType, locatorValue);
throw new RuntimeException("找不到 " + locatorType + " = '" + locatorValue + "' 的frame元素", e);
}
}
/**
* 根据定位类型和值获取Selenium定位器
* @param locatorType 定位类型(不区分大小写):
* id/name/className/tagName/linkText/partialLinkText/css/xpath/label/value/index
* @param locatorValue 定位值
* @return By 定位器对象
* @throws IllegalArgumentException 如果定位类型不支持
*/
public By getLocator(String locatorType, String locatorValue) {
if (locatorValue == null || locatorValue.trim().isEmpty()) {
throw new IllegalArgumentException("定位值不能为空");
}
switch (locatorType.toLowerCase()) {
case "id":
return By.id(locatorValue);
case "name":
return By.name(locatorValue);
case "classname":
case "class":
return By.className(locatorValue);
case "tagname":
case "tag":
return By.tagName(locatorValue);
case "linktext":
case "link":
return By.linkText(locatorValue);
case "partiallinktext":
case "partiallink":
return By.partialLinkText(locatorValue);
case "css":
case "cssselector":
return By.cssSelector(locatorValue);
case "xpath":
return By.xpath(locatorValue);
case "label":
// 通过label文本定位对应的元素
return By.xpath(String.format("//label[contains(text(), '%s')]", locatorValue));
case "value":
// 通过value属性定位
return By.xpath(String.format("//*[@value='%s']", locatorValue));
case "index":
// 索引定位需要特殊处理,通常结合其他定位方式使用
try {
int index = Integer.parseInt(locatorValue);
return By.xpath(String.format("(//*)[%d]", index + 1)); // XPath索引从1开始
} catch (NumberFormatException e) {
throw new IllegalArgumentException("索引必须是数字: " + locatorValue);
}
default:
throw new IllegalArgumentException("不支持的定位类型: " + locatorType +
"。支持的定位类型: id,name,className,tagName,linkText," +
"partialLinkText,css,xpath,label,value,index");
}
}
/**
* 处理弹窗
* @param operationType 操作类型 (1=确定, 2=取消)
* @param inputText 需要输入的文本 (可为null表示不输入)
*/
public void handleAlert(int operationType, String inputText) {
try {
Alert alert = wait.until(ExpectedConditions.alertIsPresent());
// 如果有输入文本
if (inputText != null && !inputText.isEmpty()) {
alert.sendKeys(inputText);
log.info("已在弹窗中输入文本: {}", inputText);
}
// 执行确认或取消操作
if (operationType == 1) {
alert.accept();
log.info("已确认弹窗");
} else if (operationType == 2) {
alert.dismiss();
log.info("已取消弹窗");
} else {
throw new IllegalArgumentException("无效的弹窗操作类型: " + operationType);
}
} catch (NoAlertPresentException e) {
log.error("没有找到弹窗", e);
throw new RuntimeException("当前没有可操作的弹窗", e);
} catch (TimeoutException e) {
log.error("等待弹窗超时", e);
throw new RuntimeException("等待弹窗出现超时", e);
}
}
/**
* 获取弹窗文本
* @return 弹窗显示的文本内容
*/
public String getAlertText() {
try {
Alert alert = wait.until(ExpectedConditions.alertIsPresent());
String text = alert.getText();
log.info("获取到弹窗文本: {}", text);
return text;
} catch (Exception e) {
log.error("获取弹窗文本失败", e);
throw new RuntimeException("无法获取弹窗文本", e);
}
}
/**
* 根据定位方式和定位值查找元素
* @param locType 定位方式 (如 "id", "xpath", "cssSelector" 等)
* @param locValue 定位值
* @return 找到的WebElement
*/
public WebElement findElement(String locType, String locValue) {
try {
By by = getLocator(locType, locValue);
WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(by));
return element;
} catch (Exception e) {
throw new RuntimeException("无法定位元素,定位方式:" + locType + ",定位值:" + locValue, e);
}
}
/**
* 操作下拉框
* @param element 下拉框元素
* @param optionType 选项类型 (1=选项文本, 2=索引, 3=值)
* @param optionValue 选项值
*/
public void selectDropdownOption(WebElement element, String optionType, String optionValue) {
Select select = new Select(element);
try {
switch (optionType) {
case "1": // 选项文本
select.selectByVisibleText(optionValue);
log.info("通过选项文本选择下拉框选项: {}", optionValue);
break;
case "2": // 索引
int index = Integer.parseInt(optionValue);
select.selectByIndex(index);
log.info("通过索引选择下拉框选项: {}", index);
break;
case "3": // 值
select.selectByValue(optionValue);
log.info("通过值选择下拉框选项: {}", optionValue);
break;
default:
throw new IllegalArgumentException("不支持的选项类型: " + optionType);
}
} catch (Exception e) {
log.error("操作下拉框失败", e);
throw new RuntimeException("操作下拉框失败", e);
}
}
/**
* 等待元素满足指定条件
* @param locator 元素定位器
* @param operate 操作类型:
* 1=等待元素文本等于给定值
* 2=等待元素存在
* 3=等待元素显示
* 4=等待元素不显示
* 5=等待元素不存在
* 6=等待元素可编辑
* 7=等待元素不可编辑
* @param awaitValue 等待的值(用于文本比较或自定义超时时间)
* @param timeoutInMillis 默认超时时间(毫秒)
*/
public void waitForElement(By locator, int operate, String awaitValue, long timeoutInMillis) {
WebDriverWait customWait = new WebDriverWait(driver, Duration.ofMillis(timeoutInMillis));
try {
switch (operate) {
case 1: // 等待元素文本等于给定值
customWait.until(ExpectedConditions.textToBe(locator, awaitValue));
log.info("元素文本已等于: {}", awaitValue);
break;
case 2: // 等待元素存在
customWait.until(ExpectedConditions.presenceOfElementLocated(locator));
log.info("元素已存在");
break;
case 3: // 等待元素显示
customWait.until(ExpectedConditions.visibilityOfElementLocated(locator));
log.info("元素已显示");
break;
case 4: // 等待元素不显示
customWait.until(ExpectedConditions.invisibilityOfElementLocated(locator));
log.info("元素已不显示");
break;
case 5: // 等待元素不存在
boolean isAbsent = customWait.until(ExpectedConditions.not(
ExpectedConditions.presenceOfElementLocated(locator)
));
log.info("元素已不存在");
break;
case 6: // 等待元素可编辑
customWait.until(driver -> {
WebElement element = driver.findElement(locator);
return element.isEnabled() && !element.getAttribute("readonly").equals("true");
});
log.info("元素已可编辑");
break;
case 7: // 等待元素不可编辑
customWait.until(driver -> {
WebElement element = driver.findElement(locator);
return !element.isEnabled() || element.getAttribute("readonly").equals("true");
});
log.info("元素已不可编辑");
break;
default:
throw new IllegalArgumentException("不支持的等待操作类型: " + operate);
}
} catch (TimeoutException e) {
log.error("等待元素超时,操作类型: {}, 定位器: {}", operate, locator);
throw new RuntimeException("等待元素条件未满足: " + getOperationDescription(operate), e);
}
}
// 获取操作类型描述
private String getOperationDescription(int operate) {
switch (operate) {
case 1: return "文本等于给定值";
case 2: return "元素存在";
case 3: return "元素显示";
case 4: return "元素不显示";
case 5: return "元素不存在";
case 6: return "元素可编辑";
case 7: return "元素不可编辑";
default: return "未知操作";
}
}
/**
* 执行鼠标操作
* @param locator 元素定位器
* @param clickMethod 点击方式:
* 1=单击(左键)
* 2=单击(右键)
* 3=双击
* 4=按下
* 5=弹起
*/
public void performMouseAction(By locator, int clickMethod) {
try {
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(locator));
switch (clickMethod) {
case 1: // 左键单击
actions.click(element).perform();
log.info("已执行左键单击操作");
break;
case 2: // 右键单击
actions.contextClick(element).perform();
log.info("已执行右键单击操作");
break;
case 3: // 双击
actions.doubleClick(element).perform();
log.info("已执行双击操作");
break;
case 4: // 按下
actions.clickAndHold(element).perform();
log.info("已执行鼠标按下操作");
break;
case 5: // 弹起
actions.release(element).perform();
log.info("已执行鼠标弹起操作");
break;
default:
throw new IllegalArgumentException("不支持的鼠标操作类型: " + clickMethod);
}
} catch (TimeoutException e) {
log.error("等待元素可点击超时,定位器: {}", locator);
throw new RuntimeException("元素不可点击或未找到: " + locator, e);
} catch (Exception e) {
log.error("鼠标操作执行失败", e);
throw new RuntimeException("鼠标操作失败: " + e.getMessage(), e);
}
}
/**
* 执行鼠标移动操作
* @param locator 元素定位器
* @param moveType 移动类型:
* 1=鼠标移出元素
* 2=鼠标移入元素
*/
public void performMouseMove(By locator, int moveType) {
try {
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
switch (moveType) {
case 1: // 鼠标移出元素
// 先移动到元素上,再移动到页面左上角
actions.moveToElement(element)
.moveByOffset(-element.getSize().getWidth(), -element.getSize().getHeight())
.perform();
log.info("已将鼠标从元素移出");
break;
case 2: // 鼠标移入元素(悬停)
actions.moveToElement(element).perform();
log.info("已将鼠标悬停在元素上");
break;
default:
throw new IllegalArgumentException("不支持的鼠标移动类型: " + moveType);
}
} catch (TimeoutException e) {
log.error("等待元素可见超时,定位器: {}", locator);
throw new RuntimeException("元素不可见或未找到: " + locator, e);
} catch (Exception e) {
log.error("鼠标移动操作执行失败", e);
throw new RuntimeException("鼠标移动操作失败: " + e.getMessage(), e);
}
}
/**
* 在指定元素中输入文本
* @param locator 元素定位器
* @param text 要输入的文本
* @param clearFirst 是否先清空原有内容
* @param inputMethod 输入方式:
* 1=普通输入sendKeys
* 2=通过JavaScript设置值
* 3=模拟人工输入(带延迟)
*/
public void inputText(By locator, String text, boolean clearFirst, int inputMethod) {
try {
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
// 先清空内容(如果需要)
if (clearFirst) {
element.clear();
log.info("已清空输入框内容");
}
switch (inputMethod) {
case 1: // 普通输入
element.sendKeys(text);
log.info("已通过sendKeys输入文本: {}", text);
break;
case 2: // JavaScript输入
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].value = arguments[1]", element, text);
log.info("已通过JavaScript设置文本: {}", text);
break;
case 3: // 模拟人工输入
for (char c : text.toCharArray()) {
element.sendKeys(String.valueOf(c));
Thread.sleep(50); // 每个字符间隔50ms
}
log.info("已模拟人工输入文本: {}", text);
break;
default:
throw new IllegalArgumentException("不支持的输入方式: " + inputMethod);
}
} catch (TimeoutException e) {
log.error("等待输入元素可见超时,定位器: {}", locator);
throw new RuntimeException("输入元素不可见或未找到: " + locator, e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("模拟人工输入被中断");
throw new RuntimeException("输入操作被中断", e);
} catch (Exception e) {
log.error("输入操作执行失败", e);
throw new RuntimeException("输入操作失败: " + e.getMessage(), e);
}
}
/**
* 在可编辑段落中输入文本(如富文本编辑器)
* @param locator 元素定位器
* @param text 要输入的文本
*/
public void inputToEditableDiv(By locator, String text) {
try {
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
element.click(); // 先点击激活
element.sendKeys(text);
log.info("已在可编辑段落中输入文本: {}", text);
} catch (Exception e) {
log.error("可编辑段落输入失败", e);
throw new RuntimeException("可编辑段落输入失败: " + e.getMessage(), e);
}
}
/**
* 清空输入框内容
* @param locator 元素定位器
*/
public void clearInput(By locator) {
try {
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
element.clear();
log.info("已清空输入框内容");
} catch (Exception e) {
log.error("清空输入框失败", e);
throw new RuntimeException("清空输入框失败: " + e.getMessage(), e);
}
}
/**
* 在新标签页打开URL
* @param url 要打开的网址
*/
public void openUrlInNewTab(String url) {
// 打开新标签页
driver.switchTo().newWindow(WindowType.TAB);
// 导航到目标URL
driver.get(url);
}
/**
* 数据提取提取窗口信息
* @param windowType
* @return
*/
public String extractWindowInformation(String windowType) {
switch (windowType) {
case "1": // 窗口 Handle
return driver.getWindowHandle();
case "2": // 网页标题
return driver.getTitle();
default:
throw new IllegalArgumentException("Invalid windowType: " + windowType);
}
}
/**
* 查找多个元素
* @param locType
* @param locValue
* @return
*/
public List<WebElement> findElements(String locType, String locValue) {
return driver.findElements(getLocator(locType, locValue));
}
/**
* 获取网页标题
* @return
*/
public String getTitle(){
return driver.getTitle();
}
}

View File

@@ -0,0 +1,65 @@
package com.test.common.utils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
/**
* @author liangdaliang
* @Description
* @date 2025-04-21 09:53
*/
public class UITestUtil {
public static void main(String[] args) {
// 设置 WebDriver 的路径 (根据你的实际路径修改)
System.setProperty("webdriver.chrome.driver", "E:/AA/chromedriver-win64/chromedriver.exe");
// 初始化 ChromeDriver
WebDriver driver = new ChromeDriver();
try {
// 打开目标网页的登录页面
String url = "https://sso.gxnews.com.cn/"; // 替换为实际的登录页面 URL
driver.get(url);
// 最大化浏览器窗口
driver.manage().window().maximize();
// 创建 WebDriverWait 实例,设置最大等待时间为 10 秒
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(60));
// 等待用户名输入框可见并输入用户名
WebElement usernameInput = wait.until(ExpectedConditions.visibilityOfElementLocated(By.name("username")));
usernameInput.sendKeys("ldlspace"); // 替换为实际用户名
// 等待密码输入框可见并输入密码
WebElement passwordInput = wait.until(ExpectedConditions.visibilityOfElementLocated(By.name("password")));
passwordInput.sendKeys("Ldl08844"); // 替换为实际密码
// 等待登录按钮可点击并点击
WebElement loginButton = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[@id=\"button\"]")));
loginButton.click();
Thread.sleep(3000);
String currentUrl = driver.getCurrentUrl();
System.out.println(currentUrl);
WebElement welcome = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[@id=\"list\"]/ul/li[1]")));
String welcomeText = welcome.getText();
if (welcomeText.equals("ldlspace,欢迎您登录")) {
System.out.println("登录成功!");
} else {
System.out.println("登录失败!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭浏览器
driver.quit();
}
}
}

View File

@@ -0,0 +1,62 @@
package com.test.test.controller;
import com.test.common.annotation.Log;
import com.test.common.core.controller.BaseController;
import com.test.common.core.domain.AjaxResult;
import com.test.common.core.page.TableDataInfo;
import com.test.common.enums.BusinessType;
import com.test.test.domain.PerformanceTestCaseReport;
import com.test.test.service.IPerformanceTestCaseReportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* @author liangdaliang
* @Description
* @date 2025-04-14 16:59
*/
@RestController
@RequestMapping("/test/performanceReport")
public class PerformanceReportController extends BaseController {
@Autowired
private IPerformanceTestCaseReportService performanceTestCaseReportService;
@GetMapping("/list")
public TableDataInfo list(PerformanceTestCaseReport input)
{
startPage();
input.setDelFlag("0");
List<PerformanceTestCaseReport> list = performanceTestCaseReportService.selectPerformanceTestCaseReportList(input);
return getDataTable(list);
}
/**
* 获取单个性能测试报告详细信息
*/
@GetMapping(value = "/getInfo/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(performanceTestCaseReportService.selectPerformanceTestCaseReportById(id));
}
/**
* 删除性能测试报告详细信息
*/
@Log(title = "性能测试", businessType = BusinessType.UPDATE)
@PutMapping("/delete/{id}")
public AjaxResult remove(@PathVariable Long id)
{
PerformanceTestCaseReport report = performanceTestCaseReportService.selectPerformanceTestCaseReportById(id);
if (report != null) {
report.setDelFlag("1");
report.setUpdateTime(new Date());
return toAjax(performanceTestCaseReportService.updatePerformanceTestCaseReport(report));
} else {
return null;
}
}
}

View File

@@ -0,0 +1,239 @@
package com.test.test.controller;
import com.test.common.annotation.Log;
import com.test.common.core.controller.BaseController;
import com.test.common.core.domain.AjaxResult;
import com.test.common.core.page.TableDataInfo;
import com.test.common.enums.BusinessType;
import com.test.common.utils.StringUtils;
import com.test.common.utils.poi.ExcelUtil;
import com.test.test.domain.PerformanceTest;
import com.test.test.domain.TestCase;
import com.test.test.domain.qo.PerformanceTestQO;
import com.test.test.domain.vo.PerformanceTestVO;
import com.test.test.service.IPerformanceTestCaseReportService;
import com.test.test.service.IPerformanceTestService;
import com.test.test.service.ITestCaseService;
import com.test.test.task.DynamicTaskManager;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* 性能测试Controller
*
* @author test
* @date 2025-04-14
*/
@RestController
@RequestMapping("/test/performanceTest")
@Slf4j
public class PerformanceTestController extends BaseController {
@Value("${test.jmeterHomePath:/opt/apache-jmeter}")
private String jmeterHomePath;
@Autowired
private IPerformanceTestService performanceTestService;
@Autowired
private ITestCaseService testCaseService;
@Autowired
private IPerformanceTestCaseReportService performanceTestCaseReportService;
@Autowired
private DynamicTaskManager dynamicTaskManager;
/**
* 查询性能测试列表
*/
// @PreAuthorize("@ss.hasPermi('system:test:list')")
@GetMapping("/list")
public TableDataInfo list(PerformanceTest performanceTest) {
startPage();
List<PerformanceTest> list = performanceTestService.selectPerformanceTestList(performanceTest);
return getDataTable(list);
}
@GetMapping("/testCaseList")
public TableDataInfo testCaseList(TestCase testCase) {
startPage();
List<TestCase> testCaseList = testCaseService.selectTestCaseList(testCase);
return getDataTable(testCaseList);
}
/**
* 导出性能测试列表
*/
// @PreAuthorize("@ss.hasPermi('system:test:export')")
@Log(title = "性能测试", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, PerformanceTest performanceTest) {
List<PerformanceTest> list = performanceTestService.selectPerformanceTestList(performanceTest);
ExcelUtil<PerformanceTest> util = new ExcelUtil<PerformanceTest>(PerformanceTest.class);
util.exportExcel(response, list, "性能测试数据");
}
/**
* 获取性能测试详细信息
*/
// @PreAuthorize("@ss.hasPermi('system:test:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) {
return success(performanceTestService.selectPerformanceTestById(id));
}
/**
* 新增保存性能测试
*/
// @PreAuthorize("@ss.hasPermi('system:test:add')")
@Log(title = "性能测试", businessType = BusinessType.INSERT)
@PostMapping("/add")
public AjaxResult add(@RequestBody PerformanceTestQO performanceTestQO) {
try {
Long l = performanceTestService.insertPerformanceTest(performanceTestQO);
// 获取新增的任务完整信息
PerformanceTestVO newTaskVo = performanceTestService.selectPerformanceTestById(l);
PerformanceTest entity = new PerformanceTest();
entity.setId(newTaskVo.getId());
entity.setCrontab(newTaskVo.getCrontab());
entity.setCrontabStatus(newTaskVo.getCrontabStatus());
entity.setDelFlag(newTaskVo.getDelFlag());
// 如果任务是定时任务且状态为启用,则添加到定时任务管理器
if (entity.getCrontabStatus() == 1) {
dynamicTaskManager.addNewTask(entity);
}
return success(l);
} catch (Exception e) {
log.info("新增失败!", e);
return error("新增失败!");
}
}
/**
* 新增保存并执行性能测试
*/
@Log(title = "性能测试", businessType = BusinessType.INSERT)
@PostMapping("/addAndExecute")
public AjaxResult addAndExecute(@RequestBody PerformanceTestQO performanceTestQO) {
try {
String createBy = getLoginUser().getUsername();
Long l = performanceTestService.insertPerformanceTest(performanceTestQO);
// 获取新增的任务完整信息
PerformanceTestVO newTaskVo = performanceTestService.selectPerformanceTestById(l);
PerformanceTest entity = new PerformanceTest();
entity.setId(newTaskVo.getId());
entity.setCrontab(newTaskVo.getCrontab());
entity.setCrontabStatus(newTaskVo.getCrontabStatus());
entity.setDelFlag(newTaskVo.getDelFlag());
// 如果任务是定时任务且状态为启用,则添加到定时任务管理器
if (entity.getCrontabStatus() == 1) {
dynamicTaskManager.addNewTask(entity);
}
// 执行性能测试
try {
CompletableFuture.runAsync(() -> {
performanceTestCaseReportService.executePerformanceTestAndReport(l, jmeterHomePath, 2, createBy);
});
return toAjax(true);
} catch (Exception e) {
log.error("执行失败!", e);
return error("执行失败!");
}
} catch (Exception e) {
log.error("新增并执行失败!", e);
return error("新增并执行失败!");
}
}
/**
* ·
*/
// @PreAuthorize("@ss.hasPermi('system:test:edit')")
@Log(title = "性能测试", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody PerformanceTestQO performanceTestQO) {
try {
PerformanceTestVO originalTask = performanceTestService.selectPerformanceTestById(performanceTestQO.getId());
Long l = performanceTestService.updatePerformanceTest(performanceTestQO);
PerformanceTestVO updatedTask = performanceTestService.selectPerformanceTestById(performanceTestQO.getId());
// 如果crontab或crontab_status被修改了则更新定时任务
if ((!StringUtils.isEmpty(updatedTask.getCrontab()) &&
!StringUtils.isEmpty(originalTask.getCrontab()) && !updatedTask.getCrontab().equals(originalTask.getCrontab()))
|| updatedTask.getCrontabStatus() != originalTask.getCrontabStatus()) {
PerformanceTest entity = new PerformanceTest();
entity.setId(updatedTask.getId());
entity.setCrontab(updatedTask.getCrontab());
entity.setCrontabStatus(updatedTask.getCrontabStatus());
entity.setDelFlag(updatedTask.getDelFlag());
dynamicTaskManager.updateTask(entity);
}
return success(l);
} catch (Exception e) {
log.error("修改失败!", e);
return error("修改失败!");
}
}
@Log(title = "性能测试", businessType = BusinessType.UPDATE)
@PutMapping("/editAndExecute")
public AjaxResult editAndExecute(@RequestBody PerformanceTestQO performanceTestQO) {
String createBy = getLoginUser().getUsername();
try {
PerformanceTestVO originalTask = performanceTestService.selectPerformanceTestById(performanceTestQO.getId());
Long l = performanceTestService.updatePerformanceTest(performanceTestQO);
PerformanceTestVO updatedTask = performanceTestService.selectPerformanceTestById(performanceTestQO.getId());
// 如果crontab或crontab_status被修改了则更新定时任务
if (!updatedTask.getCrontab().equals(originalTask.getCrontab())
|| updatedTask.getCrontabStatus() != originalTask.getCrontabStatus()) {
PerformanceTest entity = new PerformanceTest();
entity.setId(updatedTask.getId());
entity.setCrontab(updatedTask.getCrontab());
entity.setCrontabStatus(updatedTask.getCrontabStatus());
entity.setDelFlag(updatedTask.getDelFlag());
dynamicTaskManager.updateTask(entity);
}
try {
CompletableFuture.runAsync(() -> {
performanceTestCaseReportService.executePerformanceTestAndReport(l, jmeterHomePath, 2, createBy);
});
return toAjax(true);
} catch (Exception e) {
log.error("执行失败!", e);
return error("执行失败!"+e);
}
} catch (Exception e) {
log.error("修改并执行失败!", e);
return error("修改并执行失败!");
}
}
/**
* 删除性能测试
*/
// @PreAuthorize("@ss.hasPermi('system:test:remove')")
@Log(title = "性能测试", businessType = BusinessType.UPDATE)
@PutMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
dynamicTaskManager.removeTasks(ids);
return toAjax(performanceTestService.deletePerformanceTestByIds(ids));
}
/**
* 立即执行性能测试
*/
// @PreAuthorize("@ss.hasPermi('system:test:remove')")
@GetMapping("/executeNow")
public AjaxResult executeNow(@RequestParam Long id) {
String createBy = getLoginUser().getUsername();
CompletableFuture.runAsync(() -> {
performanceTestCaseReportService.executePerformanceTestAndReport(id, jmeterHomePath, 2, createBy);
});
return toAjax(true);
}
}

View File

@@ -6,7 +6,10 @@ import com.test.common.core.domain.AjaxResult;
import com.test.common.core.page.TableDataInfo;
import com.test.common.enums.BusinessType;
import com.test.common.utils.DateUtils;
import com.test.common.utils.SecurityUtils;
import com.test.common.utils.uuid.IdUtils;
import com.test.test.domain.TestCase;
import com.test.test.domain.TestPlanCase;
import com.test.test.domain.qo.IDQO;
import com.test.test.domain.qo.TestCaseListQO;
import com.test.test.service.ITestCaseService;
@@ -43,6 +46,16 @@ public class TestCaseController extends BaseController {
return getDataTable(list);
}
/**
* 查询测试计划可关联的用例列表
*/
@GetMapping("/planRelateList")
public TableDataInfo planRelateList(TestCaseListQO qo) {
startPage();
List<TestCase> list = testCaseService.selectValidTestPlanCaseList(qo);
return getDataTable(list);
}
/**
* 获取用例详细信息
*/
@@ -82,15 +95,43 @@ public class TestCaseController extends BaseController {
}
/**
* 执行用例
* 异步执行用例
*/
@Log(title = "用例", businessType = BusinessType.OTHER)
@PostMapping("/run")
public AjaxResult run(@RequestBody IDQO qo) {
log.info("执行用例 id:{}, jmeterHomePath:{}", qo.getId(), jmeterHomePath);
String caseSid = IdUtils.simpleUUID();
// 异步执行任务
CompletableFuture.runAsync(() -> {
testCaseService.executeTestCaseById(qo.getId(), jmeterHomePath);
testCaseService.executeTestCaseById(qo.getId(), jmeterHomePath, caseSid);
});
return toAjax(true);
}
/**
* 同步执行用例
*/
@Log(title = "用例", businessType = BusinessType.OTHER)
@PostMapping("/runSync")
public AjaxResult runSync(@RequestBody IDQO qo) {
log.info("同步执行用例 id:{}, jmeterHomePath:{}", qo.getId(), jmeterHomePath);
String caseSid = IdUtils.simpleUUID();
testCaseService.executeTestCaseById(qo.getId(), jmeterHomePath, caseSid);
return AjaxResult.success("执行成功", caseSid);
}
/**
* 异步执行测试计划用例
*/
@Log(title = "用例", businessType = BusinessType.OTHER)
@PostMapping("/runTestPlanCase")
public AjaxResult runTestPlanCase(@RequestBody TestPlanCase testPlanCase) {
String caseSid = IdUtils.simpleUUID();
testPlanCase.setExecuteBy(SecurityUtils.getUsername());
// 异步执行任务
CompletableFuture.runAsync(() -> {
testCaseService.executeTestCaseByPlanCase(testPlanCase, jmeterHomePath, caseSid);
});
return toAjax(true);
}

View File

@@ -0,0 +1,119 @@
package com.test.test.controller;
import com.test.common.annotation.Log;
import com.test.common.core.controller.BaseController;
import com.test.common.core.domain.AjaxResult;
import com.test.common.core.page.TableDataInfo;
import com.test.common.enums.BusinessType;
import com.test.common.enums.EnumDefectStatus;
import com.test.common.enums.EnumSeverityLevel;
import com.test.common.utils.poi.ExcelUtil;
import com.test.test.domain.TestDefect;
import com.test.test.domain.qo.IDQO;
import com.test.test.domain.qo.TestDefectListQO;
import com.test.test.service.ITestDefectService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* 测试缺陷Controller
*
* @author test
* @date 2025-04-22
*/
@RestController
@RequestMapping("/test/defect")
public class TestDefectController extends BaseController
{
@Autowired
private ITestDefectService testDefectService;
/**
* 查询测试缺陷列表
*/
@GetMapping("/list")
public TableDataInfo list(TestDefectListQO qo)
{
startPage();
List<TestDefect> list = testDefectService.selectTestDefectList(qo);
return getDataTable(list);
}
/**
* 导出测试缺陷列表
*/
@Log(title = "测试缺陷", businessType = BusinessType.EXPORT)
@PostMapping("/exportBug")
public void export(HttpServletResponse response,
@RequestBody TestDefectListQO qo) {
List<TestDefect> list = testDefectService.selectTestDefectList(qo);
for (TestDefect testDefect : list) {
testDefect.setStatus(EnumDefectStatus.getDescriptionByCode(testDefect.getStatus()));
testDefect.setLevel(EnumSeverityLevel.getDescriptionByCode(testDefect.getLevel()));
}
ExcelUtil<TestDefect> util = new ExcelUtil<TestDefect>(TestDefect.class);
util.exportExcel(response, list, "缺陷数据");
}
/**
* 批量导出测试缺陷列表
*/
@Log(title = "测试缺陷", businessType = BusinessType.EXPORT)
@PostMapping("/batchExportBug")
public void batchExport(HttpServletResponse response,
@RequestBody List<TestDefect> list) {
ExcelUtil<TestDefect> util = new ExcelUtil<TestDefect>(TestDefect.class);
for (TestDefect testDefect : list) {
testDefect.setStatus(EnumDefectStatus.getDescriptionByCode(testDefect.getStatus()));
testDefect.setLevel(EnumSeverityLevel.getDescriptionByCode(testDefect.getLevel()));
}
util.exportExcel(response, list, "缺陷数据");
}
/**
* 获取测试缺陷详细信息
*/
@PostMapping("/bugDetail")
public AjaxResult getInfo(@RequestBody IDQO qo)
{
return success(testDefectService.selectTestDefectById(qo.getId()));
}
/**
* 新增测试缺陷
*/
@Log(title = "测试缺陷", businessType = BusinessType.INSERT)
@PostMapping("/addBug")
public AjaxResult add(@RequestBody TestDefect testDefect)
{
return toAjax(testDefectService.insertTestDefect(testDefect));
}
/**
* 修改测试缺陷
*/
@Log(title = "测试缺陷", businessType = BusinessType.UPDATE)
@PostMapping("/editBug")
public AjaxResult edit(@RequestBody TestDefect testDefect)
{
return toAjax(testDefectService.updateTestDefect(testDefect));
}
/**
* 删除测试缺陷
*/
@Log(title = "测试缺陷", businessType = BusinessType.DELETE)
@PostMapping("/delBug")
public AjaxResult remove(@RequestBody IDQO qo)
{
TestDefect testDefect = testDefectService.selectTestDefectById(qo.getId());
testDefect.setUpdateBy(getUsername());
testDefect.setUpdateTime(new Date());
testDefect.setDelFlag("1");
return toAjax(testDefectService.updateTestDefect(testDefect));
}
}

View File

@@ -0,0 +1,91 @@
package com.test.test.controller;
import com.test.common.annotation.Log;
import com.test.common.core.controller.BaseController;
import com.test.common.core.domain.AjaxResult;
import com.test.common.core.page.TableDataInfo;
import com.test.common.enums.BusinessType;
import com.test.test.domain.TestPlanCase;
import com.test.test.domain.qo.TestPlanCaseQO;
import com.test.test.service.ITestPlanCaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 测试计划用例关联Controller
*
* @author test
* @date 2025-04-25
*/
@RestController
@RequestMapping("/test/planCase")
public class TestPlanCaseController extends BaseController
{
@Autowired
private ITestPlanCaseService testPlanCaseService;
/**
* 查询测试计划用例关联列表
*/
@GetMapping("/list")
public TableDataInfo list(TestPlanCase testPlanCase)
{
startPage();
List<TestPlanCase> list = testPlanCaseService.selectTestPlanCaseList(testPlanCase);
return getDataTable(list);
}
/**
* 导出测试计划用例关联列表
*/
// @Log(title = "测试计划用例关联", businessType = BusinessType.EXPORT)
// @PostMapping("/export")
// public void export(HttpServletResponse response, TestPlanCase testPlanCase)
// {
// List<TestPlanCase> list = testPlanCaseService.selectTestPlanCaseList(testPlanCase);
// ExcelUtil<TestPlanCase> util = new ExcelUtil<TestPlanCase>(TestPlanCase.class);
// util.exportExcel(response, list, "测试计划用例关联数据");
// }
/**
* 获取测试计划用例关联详细信息
*/
// @GetMapping(value = "/{id}")
// public AjaxResult getInfo(@PathVariable("id") Long id)
// {
// return success(testPlanCaseService.selectTestPlanCaseById(id));
// }
/**
* 新增测试计划用例关联
*/
@Log(title = "测试计划用例关联", businessType = BusinessType.INSERT)
@PostMapping(value = "/saveRelate")
public AjaxResult saveRelate(@RequestBody TestPlanCaseQO qo)
{
testPlanCaseService.saveRelate(qo);
return success(qo);
}
/**
* 修改测试计划用例关联
*/
// @Log(title = "测试计划用例关联", businessType = BusinessType.UPDATE)
// @PutMapping
// public AjaxResult edit(@RequestBody TestPlanCase testPlanCase)
// {
// return toAjax(testPlanCaseService.updateTestPlanCase(testPlanCase));
// }
/**
* 删除测试计划用例关联
*/
@Log(title = "测试计划用例关联", businessType = BusinessType.DELETE)
@PostMapping("/delRelate/{ids}")
public AjaxResult remove(@PathVariable("ids") Long[] ids)
{
return toAjax(testPlanCaseService.deleteTestPlanCaseByIds(ids));
}
}

View File

@@ -0,0 +1,101 @@
package com.test.test.controller;
import com.test.common.annotation.Log;
import com.test.common.core.controller.BaseController;
import com.test.common.core.domain.AjaxResult;
import com.test.common.core.page.TableDataInfo;
import com.test.common.enums.BusinessType;
import com.test.test.domain.TestPlan;
import com.test.test.domain.qo.IDQO;
import com.test.test.domain.qo.TestPlanAddQO;
import com.test.test.domain.qo.TestPlanListQO;
import com.test.test.domain.vo.TestPlanListVO;
import com.test.test.domain.vo.TestPlanOverviewTrendDataVO;
import com.test.test.domain.vo.TestPlanOverviewVO;
import com.test.test.service.ITestPlanService;
import jakarta.annotation.Resource;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 测试计划controller
*/
@Slf4j
@RestController
@RequestMapping("/test/testPlan")
public class TestPlanController extends BaseController {
@Resource
private ITestPlanService testPlanService;
/**
* 查询测试计划列表
*/
@GetMapping("/testPlanList")
public TableDataInfo planList(@Validated TestPlanListQO qo) {
startPage();
List<TestPlanListVO> list = testPlanService.getPlanList(qo);
return getDataTable(list);
}
/**
* 新增测试计划
*/
@Log(title = "测试计划", businessType = BusinessType.INSERT)
@PostMapping("/addPlan")
public AjaxResult addPlan(@RequestBody TestPlanAddQO testPlanAddQO) {
return toAjax(testPlanService.insertTestPlan(testPlanAddQO));
}
/**
* 删除测试计划
*/
@Log(title = "测试计划", businessType = BusinessType.DELETE)
@PostMapping("/deletePlan")
public AjaxResult deletePlan(@RequestBody IDQO qo) {
TestPlan testPlan = testPlanService.selectTestPlanById(qo.getId());
testPlan.setDelFlag("1");
return toAjax(testPlanService.updateTestPlan(testPlan));
}
/**
* 获取测试计划详细信息
*/
@PostMapping("/planDetail")
public AjaxResult getInfo(@RequestBody IDQO qo) {
return success(testPlanService.selectTestPlanById(qo.getId()));
}
/**
* 修改测试计划
*/
@Log(title = "测试计划", businessType = BusinessType.UPDATE)
@PostMapping("/updatePlan")
public AjaxResult edit(@RequestBody TestPlan testPlan) {
return toAjax(testPlanService.updateTestPlan(testPlan));
}
/**
* 获取测试计划概览信息
*/
@PostMapping("/planOverview")
public TestPlanOverviewVO selectPlanOverview(@RequestBody IDQO qo) {
return testPlanService.selectPlanOverview(qo.getId());
}
/**
* 获取测试计划用例执行趋势数据
*/
@PostMapping("/planCaseTrendData")
public List<TestPlanOverviewTrendDataVO> getPlanCaseTrendData(@RequestBody IDQO qo) {
return testPlanService.getCaseTrendData(qo.getId());
}
}

View File

@@ -0,0 +1,120 @@
package com.test.test.controller;
import com.test.common.annotation.Log;
import com.test.common.core.controller.BaseController;
import com.test.common.core.domain.AjaxResult;
import com.test.common.core.page.TableDataInfo;
import com.test.common.enums.BusinessType;
import com.test.common.utils.poi.ExcelUtil;
import com.test.test.domain.TestPlan;
import com.test.test.domain.TestPlanDefect;
import com.test.test.domain.TestProject;
import com.test.test.domain.qo.IDQO;
import com.test.test.domain.qo.TestPlanDefectQO;
import com.test.test.domain.qo.TestPlanDefectRelQO;
import com.test.test.domain.vo.TestPlanDefectVo;
import com.test.test.service.ITestPlanDefectService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 测试计划测试缺陷关联Controller
*
* @author test
* @date 2025-04-22
*/
@RestController
@RequestMapping("/testPlan/defect")
public class TestPlanDefectController extends BaseController
{
@Autowired
private ITestPlanDefectService testPlanDefectService;
/**
* 查询测试计划测试缺陷关联列表
*/
@GetMapping("/list")
public TableDataInfo list(TestPlanDefectQO testPlanDefect)
{
startPage();
List<TestPlanDefectVo> list = testPlanDefectService.selectTestPlanDefectList(testPlanDefect);
return getDataTable(list);
}
/**
* 导出测试计划测试缺陷关联列表
*/
@Log(title = "测试计划测试缺陷关联", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, TestPlanDefectQO testPlanDefect)
{
List<TestPlanDefectVo> list = testPlanDefectService.selectTestPlanDefectList(testPlanDefect);
ExcelUtil<TestPlanDefectVo> util = new ExcelUtil<TestPlanDefectVo>(TestPlanDefectVo.class);
util.exportExcel(response, list, "测试计划测试缺陷关联数据");
}
/**
* 获取测试计划测试缺陷关联详细信息
*/
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(testPlanDefectService.selectTestPlanDefectById(id));
}
/**
* 新增测试计划测试缺陷关联
*/
@Log(title = "测试计划测试缺陷关联", businessType = BusinessType.INSERT)
@PostMapping(value = "/addRelDefect")
public AjaxResult add(@RequestBody TestPlanDefectRelQO qo)
{
testPlanDefectService.insertTestPlanDefect(qo);
return success(qo);
}
/**
* 修改测试计划测试缺陷关联
*/
@Log(title = "测试计划测试缺陷关联", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody TestPlanDefect testPlanDefect)
{
return toAjax(testPlanDefectService.updateTestPlanDefect(testPlanDefect));
}
/**
* 删除测试计划测试缺陷关联
*/
@Log(title = "测试计划测试缺陷关联", businessType = BusinessType.DELETE)
@PostMapping("/delRelDefect/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(testPlanDefectService.deleteTestPlanDefectByIds(ids));
}
/**
* 查询缺陷关联测试计划列表
*/
@PostMapping("/defectPlanList")
public TableDataInfo defectPlanList(@RequestBody IDQO qo)
{
startPage();
List<TestPlan> list = testPlanDefectService.selectDefectPlanList(qo.getId());
return getDataTable(list);
}
/**
* 查询缺陷关联需求列表
*/
@PostMapping("/defectProjectList")
public TableDataInfo defectProjectList(@RequestBody IDQO qo)
{
startPage();
List<TestProject> list = testPlanDefectService.selectDefectProjectList(qo.getId());
return getDataTable(list);
}
}

View File

@@ -0,0 +1,71 @@
package com.test.test.controller;
import com.test.common.core.controller.BaseController;
import com.test.common.core.page.TableDataInfo;
import com.test.test.domain.TestCase;
import com.test.test.domain.TestDefect;
import com.test.test.domain.qo.IDQO;
import com.test.test.domain.vo.TestPlanProjectVo;
import com.test.test.service.ITestPlanProjectService;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 测试计划需求关联Controller
*
* @author test
* @date 2025-04-25
*/
@Slf4j
@RestController
@RequestMapping("/test/testPlanProject")
public class TestPlanProjectController extends BaseController {
@Autowired
private ITestPlanProjectService testPlanProjectService;
/**
* 查询测试计划需求关联列表
*/
@PostMapping("/list")
public TableDataInfo list(@RequestBody IDQO qo) {
startPage();
List<TestPlanProjectVo> list = testPlanProjectService.selectTestPlanProjectList(qo.getId());
return getDataTable(list);
}
/**
* 查询需求关联测试计划列表
*/
@PostMapping("/relatePlanList")
public TableDataInfo relatePlanList(@RequestBody IDQO qo) {
startPage();
List<TestPlanProjectVo> list = testPlanProjectService.selectRelatePlanList(qo.getId());
return getDataTable(list);
}
/**
* 查询需求关联用例列表
*/
@PostMapping("/relateCaseList")
public TableDataInfo relateCaseList(@RequestBody IDQO qo) {
startPage();
List<TestCase> list = testPlanProjectService.selectRelateCaseList(qo.getId());
return getDataTable(list);
}
/**
* 查询需求关联缺陷列表
*/
@PostMapping("/relateDefectList")
public TableDataInfo relateDefectList(@RequestBody IDQO qo) {
startPage();
List<TestDefect> list = testPlanProjectService.selectRelateDefectList(qo.getId());
return getDataTable(list);
}
}

View File

@@ -0,0 +1,108 @@
package com.test.test.controller;
import com.test.common.annotation.Log;
import com.test.common.core.controller.BaseController;
import com.test.common.core.domain.AjaxResult;
import com.test.common.core.page.TableDataInfo;
import com.test.common.enums.BusinessType;
import com.test.common.utils.poi.ExcelUtil;
import com.test.test.domain.TestProject;
import com.test.test.domain.qo.IDQO;
import com.test.test.domain.qo.TestProjectListQO;
import com.test.test.service.ITestProjectService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 需求controller
*/
@Slf4j
@RestController
@RequestMapping("/test/project")
public class TestProjectController extends BaseController {
@Resource
private ITestProjectService testProjectService;
/**
* 查询需求列表
* @param qo
* @return
*/
@GetMapping("/projectList")
public TableDataInfo projectList(@Validated TestProjectListQO qo) {
startPage();
List<TestProject> list = testProjectService.selectTestProjectList(qo);
return getDataTable(list);
}
/**
* 查询需求详情
* @param qo
* @return
*/
@PostMapping("/projectDetail")
public AjaxResult projectDetail(@RequestBody IDQO qo) {
return success(testProjectService.selectTestProjectById(qo.getId()));
}
/**
* 新增需求
*/
@Log(title = "需求", businessType = BusinessType.INSERT)
@PostMapping("/addProject")
public AjaxResult addProject(@RequestBody TestProject testProject) {
return toAjax(testProjectService.insertTestProject(testProject));
}
/**
* 删除需求
*/
@Log(title = "需求", businessType = BusinessType.DELETE)
@PostMapping("/delProject")
public AjaxResult delProject(@RequestBody IDQO qo) {
TestProject testProject = testProjectService.selectTestProjectById(qo.getId());
testProject.setDelFlag("1");
return toAjax(testProjectService.updateTestProject(testProject));
}
/**
* 修改需求
*/
@Log(title = "需求", businessType = BusinessType.UPDATE)
@PostMapping("/editProject")
public AjaxResult editProject(@RequestBody TestProject testProject) {
return toAjax(testProjectService.updateTestProject(testProject));
}
/**
* 导出需求列表
*/
@Log(title = "需求", businessType = BusinessType.EXPORT)
@PostMapping("/exportProject")
public void exportProject(HttpServletResponse response,
@RequestBody TestProjectListQO qo) {
List<TestProject> list = testProjectService.selectTestProjectList(qo);
ExcelUtil<TestProject> util = new ExcelUtil<TestProject>(TestProject.class);
util.exportExcel(response, list, "需求数据");
}
/**
* 批量导出需求列表
*/
@Log(title = "需求", businessType = BusinessType.EXPORT)
@PostMapping("/batchExportProject")
public void batchExportProject(HttpServletResponse response,
@RequestBody List<TestProject> list) {
ExcelUtil<TestProject> util = new ExcelUtil<TestProject>(TestProject.class);
util.exportExcel(response, list, "需求数据");
}
}

View File

@@ -0,0 +1,89 @@
package com.test.test.controller;
import com.test.common.annotation.Log;
import com.test.common.core.controller.BaseController;
import com.test.common.core.domain.AjaxResult;
import com.test.common.core.page.TableDataInfo;
import com.test.common.enums.BusinessType;
import com.test.test.domain.TestReport;
import com.test.test.domain.qo.IDQO;
import com.test.test.domain.qo.TestReportAddQO;
import com.test.test.domain.vo.TestReportVo;
import com.test.test.service.ITestReportService;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 测试报告Controller
*
* @author test
* @date 2025-04-25
*/
@Slf4j
@RestController
@RequestMapping("/test/testReport")
public class TestReportController extends BaseController {
@Autowired
private ITestReportService testReportService;
/**
* 查询测试计划关联测试报告列表
* @return
*/
@PostMapping("/reportList")
public TableDataInfo list(@Validated IDQO qo) {
startPage();
List<TestReportVo> list = testReportService.selectTestReportList(qo.getId());
return getDataTable(list);
}
/**
* 新增测试报告及关联测试计划
* @param testReportAddQO
* @return
*/
@Log(title = "测试报告", businessType = BusinessType.INSERT)
@PostMapping("/addTestReport")
public AjaxResult addTestReport(@RequestBody TestReportAddQO testReportAddQO) {
return toAjax(testReportService.addTestReport(testReportAddQO));
}
/**
* 查询测试计划关联测试报告详情
*/
@PostMapping("/caseExecuteDetail")
public AjaxResult caseExecuteDetail(@RequestBody IDQO id) {
return success(testReportService.selectCaseTestReportById(id.getId()));
}
/**
* 删除测试报告
* @param id
* @return
*/
@Log(title = "测试报告", businessType = BusinessType.DELETE)
@PostMapping("/delExecuteCaseReport")
public AjaxResult delExecuteCaseReport(@RequestBody IDQO id) {
TestReport testReport = testReportService.selectCaseTestReportById(id.getId());
testReport.setDelFlag("1");
return toAjax(testReportService.updateExecuteCaseReport(testReport));
}
/**
* 修改测试计划关联测试报告
* @param testReport
*/
@Log(title = "测试报告", businessType = BusinessType.UPDATE)
@PostMapping("/updateExecuteCaseReport")
public AjaxResult updateExecuteCaseReport(@RequestBody TestReport testReport) {
return toAjax(testReportService.updateExecuteCaseReport(testReport));
}
}

View File

@@ -8,9 +8,14 @@ import com.test.common.enums.BusinessType;
import com.test.common.utils.DateUtils;
import com.test.common.utils.SecurityUtils;
import com.test.test.domain.TestTask;
import com.test.test.domain.TestTaskLog;
import com.test.test.domain.TestTaskResult;
import com.test.test.domain.qo.GroupIdQO;
import com.test.test.domain.qo.IDQO;
import com.test.test.service.ITestTaskLogService;
import com.test.test.service.ITestTaskResultService;
import com.test.test.service.ITestTaskService;
import com.test.test.task.TestTaskManager;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
@@ -32,6 +37,15 @@ public class TestTaskController extends BaseController {
@Resource
private ITestTaskService testTaskService;
@Resource
private ITestTaskResultService testTaskResultService;
@Resource
private ITestTaskLogService taskLogService;
@Resource
private TestTaskManager testTaskManager;
/**
* 查询定时任务列表
*/
@@ -42,6 +56,30 @@ public class TestTaskController extends BaseController {
return getDataTable(list);
}
/**
* 查询定时任务执行记录列表
*/
@GetMapping("/taskResultListByTaskId")
public TableDataInfo taskResultListByTaskId(@Validated IDQO qo) {
startPage();
TestTaskResult testTaskResult = new TestTaskResult();
testTaskResult.setTaskId(qo.getId());
List<TestTaskResult> list = testTaskResultService.selectTestTaskResultList(testTaskResult);
return getDataTable(list);
}
/**
* 查询定时任务操作记录列表
*/
@GetMapping("/taskLogListByTaskId")
public TableDataInfo taskLogListByTaskId(@Validated IDQO qo) {
startPage();
TestTaskLog testTaskLog = new TestTaskLog();
testTaskLog.setTaskId(qo.getId());
List<TestTaskLog> list = taskLogService.selectTestTaskLogList(testTaskLog);
return getDataTable(list);
}
/**
* 获取定时任务详细信息
*/
@@ -56,9 +94,24 @@ public class TestTaskController extends BaseController {
@Log(title = "定时任务", businessType = BusinessType.INSERT)
@PostMapping("/add")
public AjaxResult add(@RequestBody TestTask testTask) {
testTask.setCreateBy(getLoginUser().getUsername());
testTask.setCreateTime(DateUtils.getNowDate());
return toAjax(testTaskService.insertTestTask(testTask));
try {
testTask.setCreateBy(getLoginUser().getUsername());
testTask.setCreateTime(DateUtils.getNowDate());
if (testTask.getStatus() == null) {
testTask.setStatus(2);
}
int result = testTaskService.insertTestTask(testTask);
// 如果任务状态是启用且没有被删除,则添加到定时任务管理器
if (testTask.getStatus() == 0 && "0".equals(testTask.getDelFlag())) {
testTaskManager.addNewTask(testTask);
}
return toAjax(result);
} catch (Exception e) {
logger.error("新增失败:", e);
return error("新增失败:" + e.getMessage());
}
}
/**
@@ -67,7 +120,25 @@ public class TestTaskController extends BaseController {
@Log(title = "定时任务", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
public AjaxResult edit(@RequestBody TestTask testTask) {
return toAjax(testTaskService.updateTestTask(testTask));
try {
testTask.setUpdateBy(getLoginUser().getUsername());
testTask.setUpdateTime(DateUtils.getNowDate());
// 获取原任务信息
TestTask originalTask = testTaskService.selectTestTaskById(testTask.getId()).getTask();
// 更新任务
int result = testTaskService.updateTestTask(testTask);
// 如果状态或crontab发生变化更新定时任务
if (testTask.getStatus() != originalTask.getStatus() ||
!testTask.getCrontab().equals(originalTask.getCrontab())) {
testTaskManager.updateTask(testTask);
}
return toAjax(result);
} catch (Exception e) {
return error("修改失败:" + e.getMessage());
}
}
/**
@@ -76,7 +147,14 @@ public class TestTaskController extends BaseController {
@Log(title = "定时任务", businessType = BusinessType.DELETE)
@PostMapping("/del")
public AjaxResult remove(@RequestBody IDQO qo) {
return toAjax(testTaskService.deleteTestTaskById(qo.getId()));
try {
// 先从定时任务管理器中移除
testTaskManager.removeTask(qo.getId());
// 再删除数据库记录
return toAjax(testTaskService.deleteTestTaskById(qo.getId()));
} catch (Exception e) {
return error("删除失败:" + e.getMessage());
}
}
/**
@@ -86,11 +164,10 @@ public class TestTaskController extends BaseController {
@PostMapping("/run")
public AjaxResult run(@RequestBody IDQO qo) {
// 异步执行任务
String username = SecurityUtils.getUsername();
CompletableFuture.runAsync(() -> {
testTaskService.executeTestTaskById(qo.getId(), 2, null, jmeterHomePath, SecurityUtils.getUsername());
testTaskService.executeTestTaskById(qo.getId(), 2, null, jmeterHomePath, username);
});
return toAjax(true);
}
}

View File

@@ -0,0 +1,127 @@
package com.test.test.controller;
import java.util.List;
import java.util.Map;
import com.test.common.utils.SeleniumUtils;
import com.test.test.domain.UiAutomation;
import com.test.test.domain.UiReport;
import com.test.test.domain.qo.UiAutomationDataQO;
import com.test.test.domain.qo.UiAutomationQO;
import com.test.test.service.IUiAutomationService;
import com.test.test.service.IUiSceneStepsService;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import com.test.common.annotation.Log;
import com.test.common.core.controller.BaseController;
import com.test.common.core.domain.AjaxResult;
import com.test.common.enums.BusinessType;
import com.test.common.core.page.TableDataInfo;
/**
* ui自动化Controller
*
* @author test
* @date 2025-04-22
*/
@RestController
@RequestMapping("/test/automation")
@Slf4j
public class UiAutomationController extends BaseController
{
@Autowired
private IUiAutomationService uiAutomationService;
@Autowired
private IUiSceneStepsService uiSceneStepsService;
/**
* 查询ui自动化列表
// */
// @PreAuthorize("@ss.hasPermi('system:automation:list')")
@GetMapping("/list")
public TableDataInfo list(UiAutomationQO uiAutomation)
{
startPage();
List<UiAutomation> list = uiAutomationService.selectUiAutomationList(uiAutomation);
return getDataTable(list);
}
/**
* 获取ui自动化详细信息
*/
// @PreAuthorize("@ss.hasPermi('system:automation:query')")
@GetMapping(value = "getInfo/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(uiAutomationService.selectUiAutomationById(id));
}
/**
* 新增ui自动化
*/
// @PreAuthorize("@ss.hasPermi('system:automation:add')")
@Log(title = "ui自动化", businessType = BusinessType.INSERT)
@PostMapping("/add")
public AjaxResult add(@RequestBody UiAutomationDataQO uiAutomationDataQO)
{
try{
log.info("新增成功!");
return success(uiAutomationService.insertUiAutomation(uiAutomationDataQO));
}catch (Exception e){
log.error("新增失败!",e);
return error("新增失败!");
}
}
/**
* 修改ui自动化
*/
// @PreAuthorize("@ss.hasPermi('system:automation:edit')")
@Log(title = "ui自动化", businessType = BusinessType.UPDATE)
@PutMapping("/update")
public AjaxResult edit(@RequestBody UiAutomationDataQO uiAutomationDataQO)
{
try{
log.info("修改成功!");
return success(uiAutomationService.updateUiAutomation(uiAutomationDataQO));
}catch (Exception e){
log.error("修改失败!",e);
return error("修改失败!");
}
}
/**
* 删除ui自动化
*/
// @PreAuthorize("@ss.hasPermi('system:automation:remove')")
@Log(title = "ui自动化", businessType = BusinessType.UPDATE)
@PutMapping("delete/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(uiAutomationService.deleteUiAutomationByIds(ids));
}
/**
* 执行场景步骤
*/
// @PreAuthorize("@ss.hasPermi('system:automation:remove')")
@GetMapping("/executeStep")
public AjaxResult executeStep(@RequestParam Long id)
{
try{
String triggerMode = "1"; //手动执行
log.info("执行完成!");
return success(uiSceneStepsService.executeStep(id,triggerMode));
} catch (Exception e) {
log.error("执行错误!",e);
return error("执行错误!"+e.getMessage());
}
}
}

View File

@@ -0,0 +1,110 @@
package com.test.test.controller;
import java.util.List;
import com.test.test.domain.UiElement;
import com.test.test.domain.qo.UiElementQO;
import com.test.test.service.IUiElementService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.test.common.annotation.Log;
import com.test.common.core.controller.BaseController;
import com.test.common.core.domain.AjaxResult;
import com.test.common.enums.BusinessType;
import com.test.common.utils.poi.ExcelUtil;
import com.test.common.core.page.TableDataInfo;
/**
* ui元素Controller
*
* @author test
* @date 2025-04-22
*/
@RestController
@RequestMapping("/test/element")
public class UiElementController extends BaseController
{
@Autowired
private IUiElementService uiElementService;
/**
* 查询ui元素列表
*/
// @PreAuthorize("@ss.hasPermi('system:element:list')")
@GetMapping("/list")
public TableDataInfo list(UiElementQO uiElement)
{
startPage();
List<UiElement> list = uiElementService.selectUiElementListNew(uiElement);
return getDataTable(list);
}
/**
* 获取ui元素详细信息
*/
// @PreAuthorize("@ss.hasPermi('system:element:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(uiElementService.selectUiElementById(id));
}
/**
* 新增ui元素
*/
// @PreAuthorize("@ss.hasPermi('system:element:add')")
@Log(title = "ui元素", businessType = BusinessType.INSERT)
@PostMapping("/add")
public AjaxResult add(@RequestBody UiElement uiElement)
{
return toAjax(uiElementService.insertUiElement(uiElement));
}
/**
* 修改ui元素
*/
// @PreAuthorize("@ss.hasPermi('system:element:edit')")
@Log(title = "ui元素", businessType = BusinessType.UPDATE)
@PutMapping("/update")
public AjaxResult edit(@RequestBody UiElement uiElement)
{
return toAjax(uiElementService.updateUiElement(uiElement));
}
/**
* 删除ui元素
*/
// @PreAuthorize("@ss.hasPermi('system:element:remove')")
@Log(title = "ui元素", businessType = BusinessType.UPDATE)
@PutMapping("delete/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(uiElementService.deleteUiElementByIds(ids));
}
// /**
// * 导出ui元素列表
// */
// @PreAuthorize("@ss.hasPermi('system:element:export')")
// @Log(title = "ui元素", businessType = BusinessType.EXPORT)
// @PostMapping("/export")
// public void export(HttpServletResponse response, UiElement uiElement)
// {
// List<UiElement> list = uiElementService.selectUiElementList(uiElement);
// ExcelUtil<UiElement> util = new ExcelUtil<UiElement>(UiElement.class);
// util.exportExcel(response, list, "ui元素数据");
// }
}

View File

@@ -0,0 +1,94 @@
package com.test.test.controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import com.test.test.domain.UiReport;
import com.test.test.service.IUiReportService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.test.common.annotation.Log;
import com.test.common.core.controller.BaseController;
import com.test.common.core.domain.AjaxResult;
import com.test.common.enums.BusinessType;
import com.test.common.utils.poi.ExcelUtil;
import com.test.common.core.page.TableDataInfo;
/**
* ui报告Controller
*
* @author test
* @date 2025-04-24
*/
@RestController
@RequestMapping("/test/report")
public class UiReportController extends BaseController
{
@Autowired
private IUiReportService uiReportService;
/**
* 查询ui报告列表
*/
// @PreAuthorize("@ss.hasPermi('system:report:list')")
@GetMapping("/list")
public TableDataInfo list(UiReport uiReport)
{
startPage();
List<UiReport> list = uiReportService.selectUiReportList(uiReport);
return getDataTable(list);
}
/**
* 获取ui报告详细信息
*/
// @PreAuthorize("@ss.hasPermi('system:report:query')")
@GetMapping(value = "getInfo/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(uiReportService.selectUiReportById(id));
}
/**
* 删除ui报告
*/
// @PreAuthorize("@ss.hasPermi('system:report:remove')")
@Log(title = "ui报告", businessType = BusinessType.UPDATE)
@PutMapping("delete/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(uiReportService.deleteUiReportByIds(ids));
}
@GetMapping("/screenshot")
public void getScreenshot(@RequestParam String path, HttpServletResponse response) throws IOException {
File file = new File(path);
if (!file.exists()) {
try {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} catch (IOException e) {
throw new RuntimeException(e);
}
return;
}
response.setContentType("image/png");
try (FileInputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream()) {
byte[] buffer = new byte[4096];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
}
}
}

View File

@@ -0,0 +1,250 @@
package com.test.test.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
/**
* 性能测试对象 performance_test
*
* @author test
* @date 2025-04-14
*/
public class PerformanceTest extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键 */
private Long id;
/** 性能测试名称 */
@Excel(name = "性能测试名称")
private String performanceName;
/** crontab表达式 */
@Excel(name = "crontab表达式")
private String crontab;
/** 定时任务状态0关闭1开启默认0 */
@Excel(name = "定时任务状态0关闭1开启默认0")
private Integer crontabStatus;
/** 并发线程数 */
@Excel(name = "并发线程数")
private Integer concurrentThreads;
/** 在取样器错误后要执行的动作1继续2开始下一个线程轮询3停止线程4停止测试5立即停止测试 */
@Excel(name = "在取样器错误后要执行的动作1继续2开始下一个线程轮询3停止线程4停止测试5立即停止测试")
private Integer errorOperType;
/** 执行方式1按持续时间2按迭代次数 */
@Excel(name = "执行方式1按持续时间2按迭代次数")
private Integer executeType;
/** 多少秒内线程建立完成默认0 */
@Excel(name = "多少秒内线程建立完成默认0")
private Integer rampUpSeconds;
/** 压测时长默认0 */
@Excel(name = "压测时长默认0")
private Integer pressureHour;
/** 压测时长默认0 */
@Excel(name = "压测时长默认0")
private Integer pressureMinute;
/** 压测时长默认0 */
@Excel(name = "压测时长默认0")
private Integer pressureSecond;
/** 迭代次数默认0 */
@Excel(name = "迭代次数默认0")
private Integer loopCount;
/** rps状态0关闭1开启默认0 */
@Excel(name = "rps状态0关闭1开启默认0")
private Integer rpsStatus;
/** 每分钟rps上限数默认0 */
@Excel(name = "每分钟rps上限数默认0")
private Integer rpsLimit;
/** 是否已执行完成状态0否1是默认0 */
@Excel(name = "是否已执行完成状态0否1是默认0")
private String status;
/** 0,正常,1,删除 */
private String delFlag;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setPerformanceName(String performanceName)
{
this.performanceName = performanceName;
}
public String getPerformanceName()
{
return performanceName;
}
public void setCrontab(String crontab)
{
this.crontab = crontab;
}
public String getCrontab()
{
return crontab;
}
public void setCrontabStatus(Integer crontabStatus)
{
this.crontabStatus = crontabStatus;
}
public Integer getCrontabStatus()
{
return crontabStatus;
}
public void setConcurrentThreads(Integer concurrentThreads)
{
this.concurrentThreads = concurrentThreads;
}
public Integer getConcurrentThreads()
{
return concurrentThreads;
}
public void setErrorOperType(Integer errorOperType)
{
this.errorOperType = errorOperType;
}
public Integer getErrorOperType()
{
return errorOperType;
}
public void setExecuteType(Integer executeType)
{
this.executeType = executeType;
}
public Integer getExecuteType()
{
return executeType;
}
public void setRampUpSeconds(Integer rampUpSeconds)
{
this.rampUpSeconds = rampUpSeconds;
}
public Integer getRampUpSeconds()
{
return rampUpSeconds;
}
public void setPressureHour(Integer pressureHour)
{
this.pressureHour = pressureHour;
}
public Integer getPressureHour()
{
return pressureHour;
}
public void setPressureMinute(Integer pressureMinute)
{
this.pressureMinute = pressureMinute;
}
public Integer getPressureMinute()
{
return pressureMinute;
}
public void setPressureSecond(Integer pressureSecond)
{
this.pressureSecond = pressureSecond;
}
public Integer getPressureSecond()
{
return pressureSecond;
}
public void setLoopCount(Integer loopCount)
{
this.loopCount = loopCount;
}
public Integer getLoopCount()
{
return loopCount;
}
public void setRpsStatus(Integer rpsStatus)
{
this.rpsStatus = rpsStatus;
}
public Integer getRpsStatus()
{
return rpsStatus;
}
public void setRpsLimit(Integer rpsLimit)
{
this.rpsLimit = rpsLimit;
}
public Integer getRpsLimit()
{
return rpsLimit;
}
public void setStatus(String status)
{
this.status = status;
}
public String getStatus()
{
return status;
}
public void setDelFlag(String delFlag)
{
this.delFlag = delFlag;
}
public String getDelFlag()
{
return delFlag;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("performanceName", getPerformanceName())
.append("crontab", getCrontab())
.append("crontabStatus", getCrontabStatus())
.append("concurrentThreads", getConcurrentThreads())
.append("errorOperType", getErrorOperType())
.append("executeType", getExecuteType())
.append("rampUpSeconds", getRampUpSeconds())
.append("pressureHour", getPressureHour())
.append("pressureMinute", getPressureMinute())
.append("pressureSecond", getPressureSecond())
.append("loopCount", getLoopCount())
.append("rpsStatus", getRpsStatus())
.append("rpsLimit", getRpsLimit())
.append("status", getStatus())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("delFlag", getDelFlag())
.toString();
}
}

View File

@@ -0,0 +1,79 @@
package com.test.test.domain;
import com.test.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.test.common.annotation.Excel;
/**
* 性能测试与测试用例关联对象 performance_test_case
*
* @author test
* @date 2025-04-14
*/
public class PerformanceTestCase extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键 */
private Long id;
/** 性能测试id逻辑外键 */
@Excel(name = "性能测试id", readConverterExp = "逻辑外键")
private Long performanceId;
/** 性能测试关联测试用例的id逻辑外键 */
@Excel(name = "性能测试关联测试用例的id", readConverterExp = "逻辑外键")
private Long testCaseId;
/** 状态0关闭1开启默认1 */
@Excel(name = "状态0关闭1开启默认1")
private Integer status;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setPerformanceId(Long performanceId)
{
this.performanceId = performanceId;
}
public Long getPerformanceId()
{
return performanceId;
}
public void setTestCaseId(Long testCaseId)
{
this.testCaseId = testCaseId;
}
public Long getTestCaseId()
{
return testCaseId;
}
public void setStatus(Integer status)
{
this.status = status;
}
public Integer getStatus()
{
return status;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("performanceId", getPerformanceId())
.append("testCaseId", getTestCaseId())
.append("status", getStatus())
.toString();
}
}

View File

@@ -0,0 +1,221 @@
package com.test.test.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import java.util.Date;
/**
* 性能测试用例报告对象 performance_test_case_report
*
* @author test
* @date 2025-04-14
*/
public class PerformanceTestCaseReport extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键ID */
private Long id;
/** 性能测试id外键 */
@Excel(name = "性能测试id", readConverterExp = "外=键")
private Long performanceId;
/** 测试用例id外键 */
@Excel(name = "测试用例id", readConverterExp = "外=键")
private Long testCaseId;
/** 性能测试执行批次id取当前系统时间戳 */
@Excel(name = "性能测试执行批次id取当前系统时间戳")
private Long sid;
/** 并发线程数 */
@Excel(name = "并发线程数")
private Integer concurrentThreads;
/** 平均响应时间(毫秒) */
@Excel(name = "平均响应时间", readConverterExp = "毫=秒")
private Long average;
/** tps */
@Excel(name = "tps")
private String tps;
/** 开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/** 结束时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
/** 耗时(毫秒) */
@Excel(name = "耗时", readConverterExp = "毫=秒")
private Long costTime;
/** 触发方式1-定时任务2-手动 */
@Excel(name = "触发方式1-定时任务2-手动")
private Integer triggerType;
/** 性能测试汇总报告json数组 */
@Excel(name = "性能测试汇总报告json数组")
private String summaryReport;
/** 性能测试错误报告json对象 */
@Excel(name = "性能测试错误报告json对象")
private String errorReport;
/** 申请人姓名 */
@Excel(name = "申请人姓名")
private String applyUser;
/** 是否已执行完成状态0否1是默认0 */
@Excel(name = "是否已执行完成状态0否1是默认0")
private String status;
/** 删除标记:0正常1删除 */
private String delFlag;
/** 用例名称 */
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getPerformanceId() {
return performanceId;
}
public void setPerformanceId(Long performanceId) {
this.performanceId = performanceId;
}
public Long getTestCaseId() {
return testCaseId;
}
public void setTestCaseId(Long testCaseId) {
this.testCaseId = testCaseId;
}
public Long getSid() {
return sid;
}
public void setSid(Long sid) {
this.sid = sid;
}
public Integer getConcurrentThreads() {
return concurrentThreads;
}
public void setConcurrentThreads(Integer concurrentThreads) {
this.concurrentThreads = concurrentThreads;
}
public Long getAverage() {
return average;
}
public void setAverage(Long average) {
this.average = average;
}
public String getTps() {
return tps;
}
public void setTps(String tps) {
this.tps = tps;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public Long getCostTime() {
return costTime;
}
public void setCostTime(Long costTime) {
this.costTime = costTime;
}
public Integer getTriggerType() {
return triggerType;
}
public void setTriggerType(Integer triggerType) {
this.triggerType = triggerType;
}
public String getSummaryReport() {
return summaryReport;
}
public void setSummaryReport(String summaryReport) {
this.summaryReport = summaryReport;
}
public String getErrorReport() {
return errorReport;
}
public void setErrorReport(String errorReport) {
this.errorReport = errorReport;
}
public String getApplyUser() {
return applyUser;
}
public void setApplyUser(String applyUser) {
this.applyUser = applyUser;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getDelFlag() {
return delFlag;
}
public void setDelFlag(String delFlag) {
this.delFlag = delFlag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -6,6 +6,8 @@ import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.Map;
/**
* 用例对象 test_case
*
@@ -47,4 +49,7 @@ public class TestCase extends BaseEntity
/** 用例会话id */
private String caseSid;
/** 存储用例上下文提取结果 */
private Map<String, String> contextResultMap;
}

View File

@@ -29,6 +29,14 @@ public class TestCaseLog extends BaseEntity
@Excel(name = "用例id")
private Long caseId;
/** 测试计划id */
@Excel(name = "测试计划id")
private Long planId;
/** 测试计划关联用例类型 */
@Excel(name = "测试计划关联用例类型")
private Integer type;
/** 操作类别 */
@Excel(name = "操作类别")
private String operType;

View File

@@ -0,0 +1,234 @@
package com.test.test.domain;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 测试缺陷对象 test_defect
*
* @author test
* @date 2025-04-22
*/
public class TestDefect extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键 */
private Long id;
/** 测试缺陷编码 */
@Excel(name = "缺陷ID")
private String serialNumber;
/** 测试缺陷名称 */
// @Excel(name = "测试缺陷名称")
private String name;
/** 缺陷概要 */
@Excel(name = "缺陷概要")
private String outline;
/** 缺陷描述 */
// @Excel(name = "缺陷描述")
private String detail;
/** 状态(0,待确认,1,修复中,2,已完成,3,无效缺陷,4,挂起,5,待验证) */
@Excel(name = "状态")
private String status;
/** 经办人 */
@Excel(name = "经办人")
private String manager;
/** 开发人员 */
// @Excel(name = "开发人员")
private String dev;
/** 严重程度0,无效,1,轻微,2,一般,3,严重,4,致命) */
@Excel(name = "严重程度")
private String level;
/** 缺陷类型0,功能逻辑,1,UI交互,2,性能问题,3,兼容性问题,4,配置错误,5,安全问题,6,安装部署,7,其他) */
// @Excel(name = "缺陷类型", readConverterExp = "0=,功能逻辑,1,UI交互,2,性能问题,3,兼容性问题,4,配置错误,5,安全问题,6,安装部署,7,其他")
private String type;
/** 是否复现0,必然复现,1,偶发复现) */
// @Excel(name = "是否复现", readConverterExp = "0=,必然复现,1,偶发复现")
private String reappearance;
/** 测试人员 */
// @Excel(name = "测试人员")
private String test;
/** 是否开启邮件通知0,不开启,1,开启) */
// @Excel(name = "是否开启邮件通知", readConverterExp = "0=,不开启,1,开启")
private String mail = "0";
/** 版本 */
// @Excel(name = "版本")
private String version;
/** 0,正常,1,删除 */
private String delFlag;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setSerialNumber(String serialNumber)
{
this.serialNumber = serialNumber;
}
public String getSerialNumber()
{
return serialNumber;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setOutline(String outline)
{
this.outline = outline;
}
public String getOutline()
{
return outline;
}
public void setDetail(String detail)
{
this.detail = detail;
}
public String getDetail()
{
return detail;
}
public void setStatus(String status)
{
this.status = status;
}
public String getStatus()
{
return status;
}
public void setManager(String manager)
{
this.manager = manager;
}
public String getManager()
{
return manager;
}
public void setDev(String dev)
{
this.dev = dev;
}
public String getDev()
{
return dev;
}
public void setLevel(String level)
{
this.level = level;
}
public String getLevel()
{
return level;
}
public void setType(String type)
{
this.type = type;
}
public String getType()
{
return type;
}
public void setReappearance(String reappearance)
{
this.reappearance = reappearance;
}
public String getReappearance()
{
return reappearance;
}
public void setTest(String test)
{
this.test = test;
}
public String getTest()
{
return test;
}
public void setMail(String mail)
{
this.mail = mail;
}
public String getMail()
{
return mail;
}
public void setVersion(String version)
{
this.version = version;
}
public String getVersion()
{
return version;
}
public void setDelFlag(String delFlag)
{
this.delFlag = delFlag;
}
public String getDelFlag()
{
return delFlag;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("serialNumber", getSerialNumber())
.append("name", getName())
.append("outline", getOutline())
.append("detail", getDetail())
.append("status", getStatus())
.append("manager", getManager())
.append("dev", getDev())
.append("level", getLevel())
.append("type", getType())
.append("reappearance", getReappearance())
.append("test", getTest())
.append("mail", getMail())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.append("version", getVersion())
.append("delFlag", getDelFlag())
.toString();
}
}

View File

@@ -0,0 +1,56 @@
package com.test.test.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* 测试计划实例表 test_plan
*/
@Getter
@Setter
@ToString
public class TestPlan extends BaseEntity {
private static final long serialVersionUID = 3214537838879582503L;
/** 主键 */
private Long id;
/** 测试计划编码 */
@Excel(name = "测试计划编码")
private String serialNumber;
/** 测试计划名称 */
@Excel(name = "测试计划名称")
private String name;
/** 状态(0,未开始,1,进行中,2,已完成,3,已终止) */
@Excel(name = "状态(0,未开始,1,进行中,2,已完成,3,已终止)")
private String status;
/** 负责人 */
@Excel(name = "负责人")
private String manager;
/** 测试计划开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "测试计划开始时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date startTime;
/** 测试计划结束时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "测试计划结束时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date endTime;
/** 版本 */
@Excel(name = "版本")
private String version;
/** 0,正常,1,删除 */
private String delFlag;
}

View File

@@ -0,0 +1,61 @@
package com.test.test.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
/**
* 测试计划用例关联对象 test_plan_case
*
* @author test
* @date 2025-04-25
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class TestPlanCase extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键 */
private Long id;
/** 测试计划主键ID */
@Excel(name = "测试计划主键ID")
private Long planId;
/** 用例主键ID */
@Excel(name = "用例主键ID")
private Long caseId;
/** 测试用例类型(0,冒烟测试,1,功能测试,2,回归测试,3,准生产测试,4,生产验证) */
@Excel(name = "测试用例类型(0,冒烟测试,1,功能测试,2,回归测试,3,准生产测试,4,生产验证)")
private Integer type;
/** 未执行、成功或失败 */
@Excel(name = "未执行、成功或失败")
private String executeResult;
/** 执行时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "执行时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date executeTime;
/** 执行人 */
@Excel(name = "执行人")
private String executeBy;
/** 版本 */
@Excel(name = "版本")
private String version;
/** 0,正常,1,删除 */
private String delFlag;
/** 未执行、成功或失败 */
@Excel(name = "用例名称")
private String caseName;
}

View File

@@ -0,0 +1,108 @@
package com.test.test.domain;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 测试计划测试缺陷关联对象 test_plan_defect
*
* @author test
* @date 2025-04-22
*/
public class TestPlanDefect extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键ID */
private Long id;
/** 测试计划主键ID */
@Excel(name = "测试计划主键ID")
private String planId;
/** 测试缺陷主键ID */
@Excel(name = "测试缺陷主键ID")
private String defectId;
/** 测试用例类型(0,冒烟测试,1,功能测试,2,回归测试,3,准生产测试,4,生产验证) */
@Excel(name = "测试用例类型(0,冒烟测试,1,功能测试,2,回归测试,3,准生产测试,4,生产验证)")
private String type;
/** 版本 */
@Excel(name = "版本")
private String version;
/** 0,正常,1,删除 */
private String delFlag;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setPlanId(String planId)
{
this.planId = planId;
}
public String getPlanId()
{
return planId;
}
public void setDefectId(String defectId)
{
this.defectId = defectId;
}
public String getDefectId()
{
return defectId;
}
public void setType(String type)
{
this.type = type;
}
public String getType()
{
return type;
}
public void setVersion(String version)
{
this.version = version;
}
public String getVersion()
{
return version;
}
public void setDelFlag(String delFlag)
{
this.delFlag = delFlag;
}
public String getDelFlag()
{
return delFlag;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("planId", getPlanId())
.append("defectId", getDefectId())
.append("type", getType())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.append("version", getVersion())
.append("delFlag", getDelFlag())
.toString();
}
}

View File

@@ -0,0 +1,34 @@
package com.test.test.domain;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
/**
* 测试计划测试项目关联需求表 test_plan_project
*
* @author test
*/
@Data
public class TestPlanProject extends BaseEntity {
private static final long serialVersionUID = 3043713502269619172L;
/** 主键 */
private Long id;
/** 需求主键ID */
@Excel(name = "需求主键ID")
private String projectId;
/** 测试计划主键ID */
@Excel(name = "测试计划主键ID")
private String planId;
/** 版本 */
@Excel(name = "版本")
private String version;
/** 0,正常,1,删除 */
private String delFlag;
}

View File

@@ -0,0 +1,36 @@
package com.test.test.domain;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
/**
* 测试计划关联测试报告表 test_plan_report
*/
@Data
public class TestPlanReport extends BaseEntity {
private static final long serialVersionUID = -1249261671553262360L;
/** 主键ID */
private Long id;
/** 测试计划主键ID */
@Excel(name = "测试计划主键ID")
private String planId;
/** 测试报告主键ID */
@Excel(name = "测试报告主键ID")
private String reportId;
/** 测试用例类型(0,冒烟测试,1,功能测试,2,回归测试,3,准生产测试,4,生产验证) */
@Excel(name = "测试用例类型(0,冒烟测试,1,功能测试,2,回归测试,3,准生产测试,4,生产验证)")
private Long type;
/** 版本 */
@Excel(name = "版本")
private String version;
/** 0,正常,1,删除 */
private String delFlag;
}

View File

@@ -0,0 +1,68 @@
package com.test.test.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class TestProject extends BaseEntity {
private static final long serialVersionUID = -8420426086386159695L;
/** 主键 */
private Long id;
/** 需求编码 */
@Excel(name = "需求编码")
private String serialNumber;
/** 需求名称 */
@Excel(name = "需求名称")
private String name;
/** 需求概要 */
@Excel(name = "需求概要")
private String outline;
/** 需求描述 */
@Excel(name = "需求描述")
private String detail;
/** 优先级(p0,p1,p2,p3,p4) */
@Excel(name = "优先级(p0,p1,p2,p3,p4)")
private String priority;
/** 预计完成时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "预计完成时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date estimatedTime;
/** 需求来源(0,产品经理,1,客户) */
@Excel(name = "需求来源(0,产品经理,1,客户)")
private String source;
/** 需求类型(0,优化,1,新功能) */
@Excel(name = "需求类型(0,优化,1,新功能)")
private String type;
/** 状态(0,未开始,1,进行中,2,已完成,3,已终止) */
@Excel(name = "状态(0,未开始,1,进行中,2,已完成,3,已终止)")
private String status;
/** 负责人 */
@Excel(name = "负责人")
private String manager;
/** 版本 */
@Excel(name = "版本")
private String version;
/** 0,正常,1,删除 */
private String delFlag;
}

View File

@@ -0,0 +1,44 @@
package com.test.test.domain;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
/**
* 测试报告表PO test_report
*/
@Data
public class TestReport extends BaseEntity {
private static final long serialVersionUID = -2614255975963227103L;
/** 主键 */
private Long id;
/** 测试报告编码 */
@Excel(name = "测试报告编码")
private String serialNumber;
/** 测试报告名称 */
@Excel(name = "测试报告名称")
private String name;
/** 测试结果(0,未通过,1,通过) */
@Excel(name = "测试结果(0,未通过,1,通过)")
private String result;
/** 测试报告发送状态0,未发送,1,已发送) */
@Excel(name = "测试报告发送状态", readConverterExp = "0=,未发送,1,已发送")
private String status;
/** 测试报告jason格式存储 */
@Excel(name = "测试报告", readConverterExp = "jason格式存储")
private String report;
/** 版本 */
@Excel(name = "版本")
private String version;
/** 0,正常,1,删除 */
private String delFlag;
}

View File

@@ -42,7 +42,7 @@ public class TestTaskLog extends BaseEntity
private String operUser;
/** 操作时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date operTime;
}

View File

@@ -30,13 +30,13 @@ public class TestTaskResult extends BaseEntity
private Long taskId;
/** 触发时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "触发时间", width = 30, dateFormat = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "触发时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date triggerTime;
/** 执行时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "执行时间", width = 30, dateFormat = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "执行时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/** 触发方式1-定时任务2-手动 */

View File

@@ -0,0 +1,232 @@
package com.test.test.domain;
import com.test.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.test.common.annotation.Excel;
/**
* ui自动化对象 ui_automation
*
* @author test
* @date 2025-04-22
*/
public class UiAutomation extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** $column.columnComment */
private Long id;
/** 模块id */
@Excel(name = "模块id")
private Long groupId;
/** 场景名称 */
@Excel(name = "场景名称")
private String name;
/** 用例等级 */
@Excel(name = "用例等级")
private String caseLevel;
/** 状态 未开始 进行中 已完成 */
@Excel(name = "状态 1未开始 2进行中 3已完成")
private String status;
/** 标签 */
@Excel(name = "标签")
private String label;
/** 责任人 */
@Excel(name = "责任人")
private String dutyBy;
/** 运行环境 */
@Excel(name = "运行环境")
private String runEnvironment;
/** 步骤数 */
@Excel(name = "步骤数")
private Integer stepsNumber;
/** 执行结果 */
@Excel(name = "执行结果")
private String executionResult;
/** 通过率 */
@Excel(name = "通过率")
private String passRate;
/** 定时任务表达式 */
@Excel(name = "定时任务表达式")
private String crontab;
/** 定时任务表达式状态 */
@Excel(name = "定时任务表达式状态")
private Integer crontabStatus;
/** 是否删除 */
private Integer delFlag;
/**描述*/
private String description;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setGroupId(Long groupId)
{
this.groupId = groupId;
}
public Long getGroupId()
{
return groupId;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setCaseLevel(String caseLevel)
{
this.caseLevel = caseLevel;
}
public String getCaseLevel()
{
return caseLevel;
}
public void setStatus(String status)
{
this.status = status;
}
public String getStatus()
{
return status;
}
public void setLabel(String label)
{
this.label = label;
}
public String getLabel()
{
return label;
}
public void setDutyBy(String dutyBy)
{
this.dutyBy = dutyBy;
}
public String getDutyBy()
{
return dutyBy;
}
public void setRunEnvironment(String runEnvironment)
{
this.runEnvironment = runEnvironment;
}
public String getRunEnvironment()
{
return runEnvironment;
}
public void setStepsNumber(Integer stepsNumber)
{
this.stepsNumber = stepsNumber;
}
public Integer getStepsNumber()
{
return stepsNumber;
}
public void setExecutionResult(String executionResult)
{
this.executionResult = executionResult;
}
public String getExecutionResult()
{
return executionResult;
}
public void setPassRate(String passRate)
{
this.passRate = passRate;
}
public String getPassRate()
{
return passRate;
}
public void setCrontab(String crontab)
{
this.crontab = crontab;
}
public String getCrontab()
{
return crontab;
}
public void setCrontabStatus(Integer crontabStatus)
{
this.crontabStatus = crontabStatus;
}
public Integer getCrontabStatus()
{
return crontabStatus;
}
public void setDelFlag(Integer delFlag)
{
this.delFlag = delFlag;
}
public Integer getDelFlag()
{
return delFlag;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("groupId", getGroupId())
.append("name", getName())
.append("caseLevel", getCaseLevel())
.append("status", getStatus())
.append("label", getLabel())
.append("createBy", getCreateBy())
.append("dutyBy", getDutyBy())
.append("runEnvironment", getRunEnvironment())
.append("updateTime", getUpdateTime())
.append("stepsNumber", getStepsNumber())
.append("executionResult", getExecutionResult())
.append("passRate", getPassRate())
.append("crontab", getCrontab())
.append("crontabStatus", getCrontabStatus())
.append("delFlag", getDelFlag())
.toString();
}
}

View File

@@ -0,0 +1,136 @@
package com.test.test.domain;
import com.test.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.test.common.annotation.Excel;
/**
* ui元素对象 ui_element
*
* @author test
* @date 2025-04-22
*/
public class UiElement extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** */
private Long id;
/** 组id */
@Excel(name = "组id")
private Long groupId;
/** 名称 */
@Excel(name = "名称")
private String name;
/** 定位类型 id name className tagName linkText partialLinkText css xpath label value index */
@Excel(name = "定位类型 id name className tagName linkText partialLinkText css xpath label value index")
private String locType;
/** 元素定位 */
@Excel(name = "元素定位")
private String elementLoc;
/** 描述 */
@Excel(name = "描述")
private String description;
/** 状态 0正常 1删除 */
private String delFlag;
/** 组路径名称(如"全部元素/测试" */
private String groupNamePath;
// getter和setter
public String getGroupNamePath() {
return groupNamePath;
}
public void setGroupNamePath(String groupNamePath) {
this.groupNamePath = groupNamePath;
}
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setGroupId(Long elementGroupId)
{
this.groupId = elementGroupId;
}
public Long getGroupId()
{
return groupId;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setLocType(String locType)
{
this.locType = locType;
}
public String getLocType()
{
return locType;
}
public void setElementLoc(String elementLoc)
{
this.elementLoc = elementLoc;
}
public String getElementLoc()
{
return elementLoc;
}
public void setDescription(String description)
{
this.description = description;
}
public String getDescription()
{
return description;
}
public void setDelFlag(String delFlag)
{
this.delFlag = delFlag;
}
public String getDelFlag()
{
return delFlag;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("groupId", getGroupId())
.append("name", getName())
.append("locType", getLocType())
.append("elementLoc", getElementLoc())
.append("description", getDescription())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("delFlag", getDelFlag())
.toString();
}
}

View File

@@ -0,0 +1,204 @@
package com.test.test.domain;
import com.test.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.test.common.annotation.Excel;
/**
* ui高级设置对象 ui_high_setting
*
* @author test
* @date 2025-04-23
*/
public class UiHighSetting extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** $column.columnComment */
private Long id;
/** 场景步骤id */
@Excel(name = "场景步骤id")
private Long sceneStepsId;
/** 设置类型 */
@Excel(name = "设置类型")
private String settingType;
/** 名称 */
@Excel(name = "名称")
private String name;
/** 操作类型 */
@Excel(name = "操作类型")
private String operateType;
/** 等待时间 */
@Excel(name = "等待时间")
private String awateTime;
/** 断言json */
@Excel(name = "断言json")
private String assertionJson;
/** 数据提取json */
@Excel(name = "数据提取json")
private String extractionDataJson;
/** 错误处理 */
@Excel(name = "错误处理")
private String errorHandling;
/** 其他设置 */
@Excel(name = "其他设置")
private String otherSetting;
/** 设置顺序 */
@Excel(name = "设置顺序")
private Integer orderNumber;
/** 是否禁用 */
@Excel(name = "是否禁用")
private Integer isDisabled;
/** 是否删除 */
private Integer delFlag;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setSceneStepsId(Long sceneStepsId)
{
this.sceneStepsId = sceneStepsId;
}
public Long getSceneStepsId()
{
return sceneStepsId;
}
public void setSettingType(String settingType)
{
this.settingType = settingType;
}
public String getSettingType()
{
return settingType;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setOperateType(String operateType)
{
this.operateType = operateType;
}
public String getOperateType()
{
return operateType;
}
public void setAwateTime(String awateTime)
{
this.awateTime = awateTime;
}
public String getAwateTime()
{
return awateTime;
}
public void setAssertionJson(String assertionJson)
{
this.assertionJson = assertionJson;
}
public String getAssertionJson()
{
return assertionJson;
}
public void setExtractionDataJson(String extractionDataJson)
{
this.extractionDataJson = extractionDataJson;
}
public String getExtractionDataJson()
{
return extractionDataJson;
}
public void setErrorHandling(String errorHandling)
{
this.errorHandling = errorHandling;
}
public String getErrorHandling()
{
return errorHandling;
}
public void setOtherSetting(String otherSetting)
{
this.otherSetting = otherSetting;
}
public String getOtherSetting()
{
return otherSetting;
}
public void setOrderNumber(Integer orderNumber)
{
this.orderNumber = orderNumber;
}
public Integer getOrderNumber()
{
return orderNumber;
}
public void setIsDisabled(Integer isDisabled)
{
this.isDisabled = isDisabled;
}
public Integer getIsDisabled()
{
return isDisabled;
}
public void setDelFlag(Integer delFlag)
{
this.delFlag = delFlag;
}
public Integer getDelFlag()
{
return delFlag;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("sceneStepsId", getSceneStepsId())
.append("settingType", getSettingType())
.append("name", getName())
.append("operateType", getOperateType())
.append("awateTime", getAwateTime())
.append("assertionJson", getAssertionJson())
.append("extractionDataJson", getExtractionDataJson())
.append("errorHandling", getErrorHandling())
.append("otherSetting", getOtherSetting())
.append("orderNumber", getOrderNumber())
.append("isDisabled", getIsDisabled())
.append("delFlag", getDelFlag())
.toString();
}
}

View File

@@ -0,0 +1,290 @@
package com.test.test.domain;
import com.test.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.test.common.annotation.Excel;
/**
* ui报告对象 ui_report
*
* @author test
* @date 2025-04-24
*/
public class UiReport extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** */
private Long id;
/** 名称 */
@Excel(name = "名称")
private String name;
/** 报告类型 */
@Excel(name = "报告类型")
private String reportType;
/** 触发方式 */
@Excel(name = "触发方式")
private String triggerMode;
/** 描述 */
@Excel(name = "描述")
private String description;
/** 是否删除 0否 1是 */
private Integer delFlag;
/** 状态 1running 2error 3 success 4stopped 5 pending 6 Timeout */
@Excel(name = "状态 1running 2error 3 success 4stopped 5 pending 6 Timeout")
private Integer status;
/** 耗时 */
@Excel(name = "耗时")
private String take;
/** 失败率 */
@Excel(name = "失败率")
private String faiiRate;
/** 成功断言 */
@Excel(name = "成功断言")
private String successAssertion;
/** 场景数 */
@Excel(name = "场景数")
private Integer scenesNumber;
/** 场景成功数 */
@Excel(name = "场景成功数")
private Integer scenesSucceedNumber;
/** 场景失败数 */
@Excel(name = "场景失败数")
private Integer scenesErrorNumber;
/** 场景未执行数 */
@Excel(name = "场景未执行数")
private Integer scenesNotNumber;
/** 步骤数 */
@Excel(name = "步骤数")
private Integer stepsNumber;
/** 步骤成功数 */
@Excel(name = "步骤成功数")
private Integer stepsSucceedNumber;
/** 步骤失败数 */
@Excel(name = "步骤失败数")
private Integer stepsErrorNumber;
/** 步骤未执行数 */
@Excel(name = "步骤未执行数")
private Integer stepsNotNumber;
private String consoleStr;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setReportType(String reportType)
{
this.reportType = reportType;
}
public String getReportType()
{
return reportType;
}
public void setTriggerMode(String triggerMode)
{
this.triggerMode = triggerMode;
}
public String getTriggerMode()
{
return triggerMode;
}
public void setDescription(String description)
{
this.description = description;
}
public String getDescription()
{
return description;
}
public void setDelFlag(Integer delFlag)
{
this.delFlag = delFlag;
}
public Integer getDelFlag()
{
return delFlag;
}
public void setStatus(Integer status)
{
this.status = status;
}
public Integer getStatus()
{
return status;
}
public void setTake(String take)
{
this.take = take;
}
public String getTake()
{
return take;
}
public void setFaiiRate(String faiiRate)
{
this.faiiRate = faiiRate;
}
public String getFaiiRate()
{
return faiiRate;
}
public void setSuccessAssertion(String successAssertion)
{
this.successAssertion = successAssertion;
}
public String getSuccessAssertion()
{
return successAssertion;
}
public void setScenesNumber(Integer scenesNumber)
{
this.scenesNumber = scenesNumber;
}
public Integer getScenesNumber()
{
return scenesNumber;
}
public void setScenesSucceedNumber(Integer scenesSucceedNumber)
{
this.scenesSucceedNumber = scenesSucceedNumber;
}
public Integer getScenesSucceedNumber()
{
return scenesSucceedNumber;
}
public void setScenesErrorNumber(Integer scenesErrorNumber)
{
this.scenesErrorNumber = scenesErrorNumber;
}
public Integer getScenesErrorNumber()
{
return scenesErrorNumber;
}
public void setScenesNotNumber(Integer scenesNotNumber)
{
this.scenesNotNumber = scenesNotNumber;
}
public Integer getScenesNotNumber()
{
return scenesNotNumber;
}
public void setStepsNumber(Integer stepsNumber)
{
this.stepsNumber = stepsNumber;
}
public Integer getStepsNumber()
{
return stepsNumber;
}
public void setStepsSucceedNumber(Integer stepsSucceedNumber)
{
this.stepsSucceedNumber = stepsSucceedNumber;
}
public Integer getStepsSucceedNumber()
{
return stepsSucceedNumber;
}
public void setStepsErrorNumber(Integer stepsErrorNumber)
{
this.stepsErrorNumber = stepsErrorNumber;
}
public Integer getStepsErrorNumber()
{
return stepsErrorNumber;
}
public void setStepsNotNumber(Integer stepsNotNumber)
{
this.stepsNotNumber = stepsNotNumber;
}
public Integer getStepsNotNumber()
{
return stepsNotNumber;
}
public String getConsoleStr() {
return consoleStr;
}
public void setConsoleStr(String consoleStr) {
this.consoleStr = consoleStr;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("name", getName())
.append("reportType", getReportType())
.append("triggerMode", getTriggerMode())
.append("description", getDescription())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("delFlag", getDelFlag())
.append("status", getStatus())
.append("take", getTake())
.append("faiiRate", getFaiiRate())
.append("successAssertion", getSuccessAssertion())
.append("scenesNumber", getScenesNumber())
.append("scenesSucceedNumber", getScenesSucceedNumber())
.append("scenesErrorNumber", getScenesErrorNumber())
.append("scenesNotNumber", getScenesNotNumber())
.append("stepsNumber", getStepsNumber())
.append("stepsSucceedNumber", getStepsSucceedNumber())
.append("stepsErrorNumber", getStepsErrorNumber())
.append("stepsNotNumber", getStepsNotNumber())
.toString();
}
}

View File

@@ -0,0 +1,400 @@
package com.test.test.domain;
import com.test.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.test.common.annotation.Excel;
/**
* ui自动化场景步骤对象 ui_scene_steps
*
* @author test
* @date 2025-04-23
*/
public class UiSceneSteps extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** */
private Long id;
/** 模块id */
@Excel(name = "模块id")
private Long automationId;
/** 操作类型 */
@Excel(name = "操作类型")
private String operateType;
/** 名称 */
@Excel(name = "名称")
private String name;
/** 步骤类型 */
@Excel(name = "步骤类型")
private String stepType;
/** url */
@Excel(name = "url")
private String url;
/** 是否追加页面 */
@Excel(name = "是否追加页面")
private Integer isAppendPage;
/** 操作 */
@Excel(name = "操作")
private Integer operate;
/** 操作对象 */
@Excel(name = "操作对象")
private String operateObject;
/** 元素库名称 */
@Excel(name = "元素库名称")
private Long operateGroupId;
/** 元素id */
@Excel(name = "元素id")
private Long operateElementId;
/** 元素定位类型 */
@Excel(name = "元素定位类型")
private String operateLocType;
/** 元素定位值 */
@Excel(name = "元素定位值")
private String operateLocValue;
/** 点击方式 */
@Excel(name = "点击方式")
private String clickMethod;
/** 输入内容 */
@Excel(name = "输入内容")
private String inputValue;
/** 窗口尺寸 */
@Excel(name = "窗口尺寸")
private String windowSize;
/** 子选项 */
@Excel(name = "子选项")
private String subOptions;
/** 子选项值 */
@Excel(name = "子选项值")
private String subOptionsValue;
/** 等待值 */
@Excel(name = "等待值")
private String awaitValue;
/** 是否禁用 */
@Excel(name = "是否禁用")
private Integer isDisabled;
/** 是否删除 */
private Integer delFlag;
/** 场景步骤序号 */
@Excel(name = "场景步骤序号")
private Integer orderNumber;
/** 句柄id */
@Excel(name = "句柄id")
private String handleId;
/** 网页索引号 */
@Excel(name = "网页索引号")
private Integer pageIndex;
/** frame索引号 */
@Excel(name = "frame索引号")
private Integer frameIndex;
/**是否输入*/
private String isEnter;
/**操作方式*/
private String operateWay;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setAutomationId(Long automationId)
{
this.automationId = automationId;
}
public Long getAutomationId()
{
return automationId;
}
public void setOperateType(String operateType)
{
this.operateType = operateType;
}
public String getOperateType()
{
return operateType;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setStepType(String stepType)
{
this.stepType = stepType;
}
public String getStepType()
{
return stepType;
}
public void setUrl(String url)
{
this.url = url;
}
public String getUrl()
{
return url;
}
public void setIsAppendPage(Integer isAppendPage)
{
this.isAppendPage = isAppendPage;
}
public Integer getIsAppendPage()
{
return isAppendPage;
}
public void setOperate(Integer operate)
{
this.operate = operate;
}
public Integer getOperate()
{
return operate;
}
public void setOperateObject(String operateObject)
{
this.operateObject = operateObject;
}
public String getOperateObject()
{
return operateObject;
}
public void setOperateGroupId(Long operateGroupId)
{
this.operateGroupId = operateGroupId;
}
public Long getOperateGroupId()
{
return operateGroupId;
}
public void setOperateElementId(Long operateElementId)
{
this.operateElementId = operateElementId;
}
public Long getOperateElementId()
{
return operateElementId;
}
public void setOperateLocType(String operateLocType)
{
this.operateLocType = operateLocType;
}
public String getOperateLocType()
{
return operateLocType;
}
public void setOperateLocValue(String operateLocValue)
{
this.operateLocValue = operateLocValue;
}
public String getOperateLocValue()
{
return operateLocValue;
}
public void setClickMethod(String clickMethod)
{
this.clickMethod = clickMethod;
}
public String getClickMethod()
{
return clickMethod;
}
public void setInputValue(String inputValue)
{
this.inputValue = inputValue;
}
public String getInputValue()
{
return inputValue;
}
public void setWindowSize(String windowSize)
{
this.windowSize = windowSize;
}
public String getWindowSize()
{
return windowSize;
}
public void setSubOptions(String subOptions)
{
this.subOptions = subOptions;
}
public String getSubOptions()
{
return subOptions;
}
public void setSubOptionsValue(String subOptionsValue)
{
this.subOptionsValue = subOptionsValue;
}
public String getSubOptionsValue()
{
return subOptionsValue;
}
public void setAwaitValue(String awaitValue)
{
this.awaitValue = awaitValue;
}
public String getAwaitValue()
{
return awaitValue;
}
public void setIsDisabled(Integer isDisabled)
{
this.isDisabled = isDisabled;
}
public Integer getIsDisabled()
{
return isDisabled;
}
public void setDelFlag(Integer delFlag)
{
this.delFlag = delFlag;
}
public Integer getDelFlag()
{
return delFlag;
}
public void setOrderNumber(Integer orderNumber)
{
this.orderNumber = orderNumber;
}
public Integer getOrderNumber()
{
return orderNumber;
}
public void setHandleId(String handleId)
{
this.handleId = handleId;
}
public String getHandleId()
{
return handleId;
}
public void setPageIndex(Integer pageIndex)
{
this.pageIndex = pageIndex;
}
public Integer getPageIndex()
{
return pageIndex;
}
public void setFrameIndex(Integer frameIndex)
{
this.frameIndex = frameIndex;
}
public Integer getFrameIndex()
{
return frameIndex;
}
public String getOperateWay() {
return operateWay;
}
public void setOperateWay(String operateWay) {
this.operateWay = operateWay;
}
public String getIsEnter() {
return isEnter;
}
public void setIsEnter(String isEnter) {
this.isEnter = isEnter;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("automationId", getAutomationId())
.append("operateType", getOperateType())
.append("name", getName())
.append("stepType", getStepType())
.append("url", getUrl())
.append("isAppendPage", getIsAppendPage())
.append("operate", getOperate())
.append("operateObject", getOperateObject())
.append("operateGroupId", getOperateGroupId())
.append("operateElementId", getOperateElementId())
.append("operateLocType", getOperateLocType())
.append("operateLocValue", getOperateLocValue())
.append("clickMethod", getClickMethod())
.append("inputValue", getInputValue())
.append("windowSize", getWindowSize())
.append("subOptions", getSubOptions())
.append("subOptionsValue", getSubOptionsValue())
.append("awaitValue", getAwaitValue())
.append("isDisabled", getIsDisabled())
.append("delFlag", getDelFlag())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("orderNumber", getOrderNumber())
.append("handleId", getHandleId())
.append("pageIndex", getPageIndex())
.append("frameIndex", getFrameIndex())
.toString();
}
}

View File

@@ -0,0 +1,167 @@
package com.test.test.domain;
import com.test.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.test.common.annotation.Excel;
/**
* ui自动化场景报告对象 ui_scene_steps_report
*
* @author test
* @date 2025-04-24
*/
public class UiSceneStepsReport extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** $column.columnComment */
private Long id;
/** 报告id */
@Excel(name = "报告id")
private Long reportId;
/** 名称 */
@Excel(name = "名称")
private String name;
/** 日志 */
@Excel(name = "日志")
private String logInfo;
/** 执行类型 1成功 0未执行 2执行失败 */
@Excel(name = "执行类型 1成功 0未执行 2执行失败")
private String executionFlag;
/** 耗时 */
@Excel(name = "耗时")
private String take;
/** 截图 */
@Excel(name = "截图")
private String screenshot;
/** 断言json */
@Excel(name = "断言json")
private String assertionJson;
/** 数据提取json */
@Excel(name = "数据提取json")
private String extractionDataJson;
/** 场景步骤序号 */
@Excel(name = "场景步骤序号")
private Integer orderNumber;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setReportId(Long reportId)
{
this.reportId = reportId;
}
public Long getReportId()
{
return reportId;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setLogInfo(String logInfo)
{
this.logInfo = logInfo;
}
public String getLogInfo()
{
return logInfo;
}
public void setExecutionFlag(String executionFlag)
{
this.executionFlag = executionFlag;
}
public String getExecutionFlag()
{
return executionFlag;
}
public void setTake(String take)
{
this.take = take;
}
public String getTake()
{
return take;
}
public void setScreenshot(String screenshot)
{
this.screenshot = screenshot;
}
public String getScreenshot()
{
return screenshot;
}
public void setAssertionJson(String assertionJson)
{
this.assertionJson = assertionJson;
}
public String getAssertionJson()
{
return assertionJson;
}
public void setExtractionDataJson(String extractionDataJson)
{
this.extractionDataJson = extractionDataJson;
}
public String getExtractionDataJson()
{
return extractionDataJson;
}
public void setOrderNumber(Integer orderNumber)
{
this.orderNumber = orderNumber;
}
public Integer getOrderNumber()
{
return orderNumber;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("reportId", getReportId())
.append("name", getName())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("logInfo", getLogInfo())
.append("executionFlag", getExecutionFlag())
.append("take", getTake())
.append("screenshot", getScreenshot())
.append("assertionJson", getAssertionJson())
.append("extractionDataJson", getExtractionDataJson())
.append("orderNumber", getOrderNumber())
.toString();
}
}

View File

@@ -0,0 +1,21 @@
package com.test.test.domain.qo;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class AssertionConfigQO {
/** 弹窗文本数组 */
private List<AssertionQO> popupTexts = new ArrayList<>();
/** 元素断言数组 */
private List<AssertionQO> elementAssertions = new ArrayList<>();
/** 下拉框数组 */
private List<AssertionQO> dropdownBoxes = new ArrayList<>();
/** 网页标题数组 */
private List<AssertionQO> webTitles = new ArrayList<>();
}

View File

@@ -0,0 +1,56 @@
package com.test.test.domain.qo;
import lombok.Data;
/**
* 断言
*/
@Data
public class AssertionQO {
/**断言类型 1断言值 2弹窗文本 3元素断言 4下拉框 5网页标题*/
private String assertionType;
/**网页标题*/
private String pageTitle;
/** 操作对象 1元素对象 2元素定位*/
private String operateObject;
/** 元素库名称 */
private Long operateGroupId;
/** 元素id */
private Long operateElementId;
/** 元素定位类型 id css ……*/
private String operateLocType;
/** 元素定位值 */
private String operateLocValue;
/**元素属性*/
private String elementAttribute;
/**断言方式*/
private String assertionMode;
/**期望值*/
private String expectations;
/**变量*/
private String variable;
/**条件 1等于 2不等于 3包含 ……*/
private String condition;
/**是否为弹窗文本*/
private String isPopText;
/**失败是否中止 0否 1是*/
private String isFailedAbort;
/**是否禁用 0否 1是*/
private Integer isDisabled;
}

View File

@@ -0,0 +1,16 @@
package com.test.test.domain.qo;
import lombok.Data;
import java.util.List;
/**
* 数据提取配置(新版嵌套结构)
*/
@Data
public class DataExtractionConfigQO {
/** 窗口信息提取配置 */
private List<DataExtractionQO> windowExtractions;
/** 元素信息提取配置 */
private List<DataExtractionQO> elementExtractions;
}

View File

@@ -0,0 +1,47 @@
package com.test.test.domain.qo;
import lombok.Data;
/**
* 数据提取
*/
@Data
public class DataExtractionQO {
/** 1提取窗口信息 2提取元素信息 */
private String informationType;
/** informationType为2时 1普通对象(store) 2元素文本(storeText) 3元素值(storeValue) 4元素属性(storeAttribute)
* 5CSS属性(storeCssAttribute) 6匹配 xpath 的元素数量(storeXpathCount) */
private String elementType;
/** informationType为1时 1窗口 Handle(storeWindowHandle) 2网页标题(storeTitle) */
private String windowType;
/**值 */
private String value;
/** 操作对象 1元素对象 2元素定位*/
private String operateObject;
/** 元素库名称 */
private Long operateGroupId;
/** 元素id */
private Long operateElementId;
/** 元素定位类型 id css ……*/
private String operateLocType;
/** 元素定位值 */
private String operateLocValue;
/** 普通对象 元素属性 元素css属性*/
private String elementAttribute;
/**是否禁用 0否 1是 */
private Integer isDisabled;
}

View File

@@ -3,6 +3,6 @@ package com.test.test.domain.qo;
import lombok.Data;
@Data
public class IDQO {
public class IDQO extends InheritQO{
private Long id;
}

View File

@@ -0,0 +1,14 @@
package com.test.test.domain.qo;
import java.io.Serializable;
import lombok.Data;
@Data
public class InheritQO implements Serializable {
private static final long serialVersionUID = -6405523005491017445L;
private Integer pageNum;
private Integer pageSize;
}

View File

@@ -0,0 +1,9 @@
package com.test.test.domain.qo;
import lombok.Data;
@Data
public class OtherSettingsQO {
private Integer waitElementTime;
private Integer screenshotConfiguration;
}

View File

@@ -0,0 +1,13 @@
package com.test.test.domain.qo;
import lombok.Data;
@Data
public class PerformanceTestCaseQO {
/** 性能测试id逻辑外键 */
private Long performanceId;
/** 性能测试关联测试用例的id逻辑外键 */
private Long testCaseId;
/** 状态0关闭1开启默认1 */
private Integer status;
}

View File

@@ -0,0 +1,47 @@
package com.test.test.domain.qo;
import com.test.common.core.domain.BaseEntity;
import com.test.test.domain.vo.PerformanceTestCaseVO;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class PerformanceTestQO extends BaseEntity {
/** 主键 */
private Long id;
/** 性能测试名称 */
private String performanceName;
/** crontab表达式 */
private String crontab;
/** 定时任务状态0关闭1开启默认0 */
private Integer crontabStatus;
/** 并发线程数 */
private Integer concurrentThreads;
/** 在取样器错误后要执行的动作1继续2开始下一个线程轮询3停止线程4停止测试5立即停止测试 */
private Integer errorOperType;
/** 执行方式1按持续时间2按迭代次数 */
private Integer executeType;
/** 多少秒内线程建立完成默认0 */
private Integer rampUpSeconds;
/** 压测时长默认0 */
private Integer pressureHour;
/** 压测时长默认0 */
private Integer pressureMinute;
/** 压测时长默认0 */
private Integer pressureSecond;
/** 迭代次数默认0 */
private Integer loopCount;
/** rps状态0关闭1开启默认0 */
private Integer rpsStatus;
/** 每分钟rps上限数默认0 */
private Integer rpsLimit;
/** 是否已执行完成状态0否1是默认0 */
private String status;
/** 0,正常,1,删除 */
private String delFlag;
private List<PerformanceTestCaseQO> performanceTestCaseVOList = new ArrayList<>();
}

View File

@@ -3,8 +3,18 @@ package com.test.test.domain.qo;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serializable;
@Data
public class TestCaseListQO {
public class TestCaseListQO implements Serializable {
private static final long serialVersionUID = 4636502018355979101L;
@NotNull(message = "父节点id不能为空")
private Long groupId;
/** 测试计划主键ID */
private Long planId;
/**
* 测试用例类型(0,冒烟测试,1,功能测试,2,回归测试,3,准生产测试,4,生产验证)
*/
private Integer type;
}

View File

@@ -0,0 +1,52 @@
package com.test.test.domain.qo;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* @author liangdaliang
* @Description查询缺陷列表请求参数qo
* @date 2025-04-22 23:54
*/
@Data
public class TestDefectListQO implements Serializable {
private static final long serialVersionUID = 4632212018365973101L;
/**
* 缺陷编码
*/
private String serialNumber;
/**
* 缺陷概要
*/
private String outline;
/**
* 开始创建时间
*/
private Date startCreateTime;
/**
* 结束创建时间
*/
private Date endCreateTime;
/**
* 经办人
*/
private String manager;
/**
* 严重程度0,无效,1,轻微,2,一般,3,严重,4,致命)
*/
private String level;
/**
* 状态(0,待确认,1,修复中,2,已完成,3,无效缺陷,4,挂起,5,待验证)
*/
private String status;
}

View File

@@ -0,0 +1,52 @@
package com.test.test.domain.qo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.test.common.core.domain.BaseEntity;
import java.util.Date;
import lombok.Data;
/**
* 测试计划新增请求QO
*
* @author pfl
*/
@Data
public class TestPlanAddQO extends BaseEntity {
private static final long serialVersionUID = 3693196640830164441L;
/** 主键id */
private Long id;
/** 测试计划id */
private Long planId;
/** 测试计划编码 */
private String serialNumber;
/** 测试计划名称 */
private String name;
/** 状态(0,未开始,1,进行中,2,已完成,3,已终止) */
private String status;
/** 负责人 */
private String manager;
/** 测试计划开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
private Date startTime;
/** 测试计划结束时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
private Date endTime;
/** 版本 */
private String version;
/** 0,正常,1,删除 */
private String delFlag;
/** 关联需求id */
private Long projectId;
}

View File

@@ -0,0 +1,20 @@
package com.test.test.domain.qo;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @author liangdaliang
* @Description测试计划关联用例
* @date 2025-04-27 13:16
*/
@Data
public class TestPlanCaseQO implements Serializable {
private static final long serialVersionUID = 4636202018365979101L;
private Long planId;
private Integer type;
private List<Long> testCaseIdList;
}

View File

@@ -0,0 +1,38 @@
package com.test.test.domain.qo;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
/**
* 测试计划测试缺陷关联请求QO
*/
@Data
public class TestPlanDefectQO extends BaseEntity {
private static final long serialVersionUID = 3754531916096288164L;
/** 主键ID */
private Long id;
/** 测试计划主键ID */
private String planId;
/** 测试缺陷主键ID */
private String defectId;
/**
* 缺陷编码
*/
private String serialNumber;
/**
* 缺陷概要
*/
private String outline;
/** 测试用例类型(0,冒烟测试,1,功能测试,2,回归测试,3,准生产测试,4,生产验证) */
private String type;
/** 版本 */
private String version;
}

View File

@@ -0,0 +1,18 @@
package com.test.test.domain.qo;
import java.io.Serializable;
import java.util.List;
import lombok.Data;
/**
* 测试计划缺陷关联
*/
@Data
public class TestPlanDefectRelQO implements Serializable {
private static final long serialVersionUID = 4779866915656657001L;
private Long planId;
private Integer type;
private List<Long> defectIdList;
}

View File

@@ -0,0 +1,52 @@
package com.test.test.domain.qo;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* 查询测试计划列表请求参数qo
*
* @author pfl
*/
@Data
public class TestPlanListQO implements Serializable {
private static final long serialVersionUID = -1058615526393949211L;
/**
* 状态
*/
private String status;
/**
* 负责人
*/
private String manager;
/**
* 测试计划名称
*/
private String name;
/**
* 测试计划开始时间起始时间
*/
private Date startPlanTime;
/**
* 测试计划开始时间结束时间
*/
private Date endPlanTime;
/**
* 测试计划截止时间起始时间
*/
private Date startDeadline;
/**
* 测试计划截止时间结束时间
*/
private Date endDeadline;
}

View File

@@ -0,0 +1,51 @@
package com.test.test.domain.qo;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* 查询需求列表请求参数qo
*
* @author pfl
*/
@Data
public class TestProjectListQO implements Serializable {
private static final long serialVersionUID = 4632218018365273102L;
/**
* 需求编码
*/
private String serialNumber;
/**
* 需求概要
*/
private String outline;
/**
* 开始创建时间
*/
private Date startCreateTime;
/**
* 结束创建时间
*/
private Date endCreateTime;
/**
* 负责人
*/
private String manager;
/**
* 优先级(p0,p1,p2,p3,p4)
*/
private String priority;
/**
* 状态(0,未开始,1,进行中,2,已完成,3,已终止)
*/
private String status;
}

View File

@@ -0,0 +1,49 @@
package com.test.test.domain.qo;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
/**
* 测试报告新增参数QO
*/
@Data
public class TestReportAddQO extends BaseEntity {
private static final long serialVersionUID = -6325566452451878775L;
/**
* 测试报告id
*/
private Long reportId;
/**
* 测试计划id
*/
private Long planId;
/**
* 测试用例类型(0,冒烟测试,1,功能测试,2,回归测试,3,准生产测试,4,生产验证)
*/
private String type;
/** 测试报告编码 */
private String serialNumber;
/** 测试报告名称 */
private String name;
/** 测试结果(0,未通过,1,通过) */
private String result;
/** 测试报告发送状态0,未发送,1,已发送) */
private String status;
/** 测试报告jason格式存储 */
private String report;
/** 版本 */
private String version;
/** 0,正常,1,删除 */
private String delFlag;
}

View File

@@ -0,0 +1,69 @@
package com.test.test.domain.qo;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* ui自动化对象 ui_automation
*
* @author test
* @date 2025-04-22
*/
@Data
public class UiAutomationDataQO extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** $column.columnComment */
private Long id;
/** 模块id */
private Long groupId;
/** 场景名称 */
private String name;
/** 用例等级 */
private String caseLevel;
/** 状态 0未开始 1进行中 2已完成 */
private String status;
/** 标签 */
private String label;
/** 责任人 */
private String dutyBy;
/** 运行环境 */
private String runEnvironment;
/** 步骤数 */
private Long stepsNumber;
/** 执行结果 */
private String executionResult;
/** 通过率 */
private String passRate;
/** 定时任务表达式 */
private String crontab;
/** 定时任务表达式状态 */
private Long crontabStatus;
/** 是否删除 */
private Long delFlag;
/**描述*/
private String description;
/** 场景步骤 */
private List<UiSceneStepsQO> uiSceneStepsVOList = new ArrayList<>();
}

View File

@@ -0,0 +1,48 @@
package com.test.test.domain.qo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.Date;
import java.util.List;
/**
* ui自动化对象 ui_automation
*
* @author test
* @date 2025-04-22
*/
@Data
public class UiAutomationQO extends BaseEntity
{
/** 名称 */
private String name;
/** 状态 0正常 1删除 */
private String delFlag;
@NotNull(message = "节点id不能为空")
private Long groupId;
private List<Long> groupIds;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
private String createBy;
/** 状态 0未开始 1进行中 2已完成 */
private String status;
private String keyword;
}

View File

@@ -0,0 +1,30 @@
package com.test.test.domain.qo;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.List;
/**
* ui元素对象 ui_element
*
* @author test
* @date 2025-04-22
*/
@Data
public class UiElementQO
{
/** 名称 */
private String name;
/** 状态 0正常 1删除 */
private String delFlag;
private Long groupId;
private List<Long> groupIds;
}

View File

@@ -0,0 +1,68 @@
package com.test.test.domain.qo;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* ui高级设置对象 ui_high_setting
*
* @author test
* @date 2025-04-23
*/
@Data
public class UiHighSettingQO extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** $column.columnComment */
private Long id;
/** 场景步骤id */
private Long sceneStepsId;
/** 设置类型 */
private String settingType;
/** 名称 */
private String name;
/** 操作类型 */
private String operateType;
/** 等待时间 */
private String awateTime;
/** 断言json */
private String assertionJson;
/** 数据提取json */
private String extractionDataJson;
/** 错误处理 */
private String errorHandling;
/** 其他设置 */
private String otherSetting;
/** 设置顺序 */
private Integer orderNumber;
/** 是否禁用 */
private Integer isDisabled;
/** 是否删除 */
private Integer delFlag;
/**其他设置*/
OtherSettingsQO otherSettingsQO = new OtherSettingsQO();
/**数据提取*/
private DataExtractionConfigQO dataExtractionQOList = new DataExtractionConfigQO();
/**断言*/
private AssertionConfigQO assertionQOList = new AssertionConfigQO();
}

View File

@@ -0,0 +1,110 @@
package com.test.test.domain.qo;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import com.test.test.domain.UiHighSetting;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.ArrayList;
import java.util.List;
/**
* ui自动化场景步骤对象 ui_scene_steps
*
* @author test
* @date 2025-04-23
*/
@Data
public class UiSceneStepsQO extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** */
private Long id;
/** 模块id */
private Long automationId;
/** 操作类型 */
private String operateType;
/** 名称 */
private String name;
/** 步骤类型 */
private String stepType;
/** url */
private String url;
/** 是否追加页面 */
private Integer isAppendPage;
/** 操作 */
private Integer operate;
/** 操作对象 */
private String operateObject;
/** 元素库名称 */
private Long operateGroupId;
/** 元素id */
private Long operateElementId;
/** 元素定位类型 */
private String operateLocType;
/** 元素定位值 */
private String operateLocValue;
/** 点击方式 */
private String clickMethod;
/** 输入内容 */
private String inputValue;
/** 窗口尺寸 */
private String windowSize;
/** 子选项 */
private String subOptions;
/** 子选项值 */
private String subOptionsValue;
/** 等待值 */
private String awaitValue;
/** 是否禁用 */
private Integer isDisabled;
/** 是否删除 */
private Integer delFlag;
/** 场景步骤序号 */
private Integer orderNumber;
/** 句柄id */
private String handleId;
/** 网页索引号 */
private Integer pageIndex;
/** frame索引号 */
private Integer frameIndex;
/**是否输入*/
private String isEnter;
/**操作方式*/
private String operateWay;
/**高级设置*/
private List<UiHighSettingQO> uiHighSettingVOList = new ArrayList<>();
}

View File

@@ -0,0 +1,25 @@
package com.test.test.domain.vo;
import lombok.Data;
/**
* 断言报告结果
*/
@Data
public class AssertionReportVO {
/**
* 断言名称
*/
private String name;
/**
* 错误信息
*/
private String errorInfo;
/**
* 是否成功 0否 1是
*/
private String isSuccess;
}

View File

@@ -0,0 +1,18 @@
package com.test.test.domain.vo;
import com.test.common.annotation.Excel;
import lombok.Data;
@Data
public class PerformanceTestCaseVO {
/** 主键 */
private Long id;
/** 性能测试id逻辑外键 */
private Long performanceId;
/** 性能测试关联测试用例的id逻辑外键 */
private Long testCaseId;
/** 性能测试关联测试用例的名称 */
private String testCaseName;
/** 状态0关闭1开启默认1 */
private Integer status;
}

View File

@@ -0,0 +1,47 @@
package com.test.test.domain.vo;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class PerformanceTestVO extends BaseEntity {
/** 主键 */
private Long id;
/** 性能测试名称 */
private String performanceName;
/** crontab表达式 */
private String crontab;
/** 定时任务状态0关闭1开启默认0 */
private Integer crontabStatus;
/** 并发线程数 */
private Integer concurrentThreads;
/** 在取样器错误后要执行的动作1继续2开始下一个线程轮询3停止线程4停止测试5立即停止测试 */
private Integer errorOperType;
/** 执行方式1按持续时间2按迭代次数 */
private Integer executeType;
/** 多少秒内线程建立完成默认0 */
private Integer rampUpSeconds;
/** 压测时长默认0 */
private Integer pressureHour;
/** 压测时长默认0 */
private Integer pressureMinute;
/** 压测时长默认0 */
private Integer pressureSecond;
/** 迭代次数默认0 */
private Integer loopCount;
/** rps状态0关闭1开启默认0 */
private Integer rpsStatus;
/** 每分钟rps上限数默认0 */
private Integer rpsLimit;
/** 是否已执行完成状态0否1是默认0 */
private String status;
/** 0,正常,1,删除 */
private String delFlag;
private List<PerformanceTestCaseVO> performanceTestCaseVOList = new ArrayList<>();
}

View File

@@ -0,0 +1,18 @@
package com.test.test.domain.vo;
import java.io.Serializable;
import lombok.Data;
@Data
public class TestCaseReportVO implements Serializable {
private static final long serialVersionUID = 6972995415807958849L;
private String name;
private String result;
private Integer caseNum;
private Integer passNum;
}

View File

@@ -0,0 +1,48 @@
package com.test.test.domain.vo;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
/**
* 测试计划测试缺陷关联返回Vo
*/
@Data
public class TestPlanDefectVo extends BaseEntity {
private static final long serialVersionUID = -4826790211276641073L;
/**
* 主键ID
*/
private Long id;
/**
* 测试计划关联缺陷ID
*/
private String defectId;
/**
* 测试计划关联缺陷ID
*/
private String serialNumber;
/**
* 测试计划关联缺陷概要
*/
private String summary;
/**
* 测试计划关联缺陷状态
*/
private String status;
/**
* 测试计划关联缺陷经办人
*/
private String manager;
/**
* 测试计划关联缺陷严重程度
*/
private String level;
}

View File

@@ -0,0 +1,83 @@
package com.test.test.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import java.util.Date;
import lombok.Data;
@Data
public class TestPlanListVO extends BaseEntity {
private static final long serialVersionUID = 7768851691630986105L;
/** 主键 */
private Long id;
/** 测试计划编码 */
@Excel(name = "测试计划编码")
private String serialNumber;
/** 测试计划名称 */
@Excel(name = "测试计划名称")
private String name;
/** 0 冒烟测试 */
private String smokeTest;
/** 1 功能测试 */
private String functionTest;
/** 2 回归测试 */
private String regressionTest;
/** 3 准生产测试 */
private String preProductionTest;
/** 4 生产测试 */
private String productionTest;
/** 冒烟测试通过数 */
private String smokeTestPassNum;
/** 功能测试通过数 */
private String functionTestPassNum;
/** 回归测试通过数 */
private String regressionTestPassNum;
/** 准生产测试通过数 */
private String preProductionTestPassNum;
/** 生产测试通过数 */
private String productionTestPassNum;
/** 状态(0,未开始,1,进行中,2,已完成,3,已终止) */
@Excel(name = "状态(0,未开始,1,进行中,2,已完成,3,已终止)")
private String status;
/** 负责人 */
@Excel(name = "负责人")
private String manager;
/** 测试计划开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "测试计划开始时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date startTime;
/** 测试计划结束时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "测试计划结束时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date endTime;
/** 版本 */
@Excel(name = "版本")
private String version;
/** 0,正常,1,删除 */
private String delFlag;
/** 缺陷数量 */
@Excel(name = "缺陷数量")
private String defectNum;
}

View File

@@ -0,0 +1,22 @@
package com.test.test.domain.vo;
import java.io.Serializable;
import lombok.Data;
@Data
public class TestPlanOverviewTrendDataVO implements Serializable {
private static final long serialVersionUID = -6444876575138174061L;
private String caseTrendDates;
private Integer notExecuted;
private Integer passed;
private Integer failed;
private Integer blocked;
private Integer skipped;
}

View File

@@ -0,0 +1,146 @@
package com.test.test.domain.vo;
import java.io.Serializable;
import java.util.List;
import lombok.Data;
@Data
public class TestPlanOverviewVO implements Serializable {
private static final long serialVersionUID = -2634301979620606338L;
/**
* 用例总数
*/
private Integer caseCount;
/**
* 已执行用例数
*/
private Integer executedCaseCount;
/**
* 用例通过数
*/
private Integer passedCaseCount;
/**
* 用例失败数
*/
private Integer failedCaseCount;
/**
* 用例阻塞数
*/
private Integer blockedCaseCount;
/**
* 用例跳过数
*/
private Integer skippedCaseCount;
/**
* 用例未执行数
*/
private Integer notExecutedCaseCount;
/**
* 缺陷数
*/
private Integer defectCount;
/**
* 待确认缺陷状态数
*/
private Integer unconfirmedDefectCount;
/**
* 修复中缺陷状态数
*/
private Integer fixingDefectCount;
/**
* 待验证缺陷状态数
*/
private Integer unverifiedDefectCount;
/**
* 无效缺陷状态数
*/
private Integer invalidDefectCount;
/**
* 挂起缺陷状态数
*/
private Integer suspendedDefectCount;
/**
* 无效等级缺陷数
*/
private Integer invalidLevelDefectCount;
/**
* 轻微等级缺陷数
*/
private Integer minorLevelDefectCount;
/**
* 一般等级缺陷数
*/
private Integer normalLevelDefectCount;
/**
* 严重等级缺陷数
*/
private Integer seriousLevelDefectCount;
/**
* 致命等级缺陷数
*/
private Integer fatalLevelDefectCount;
/**
* 功能逻辑类型缺陷数
*/
private Integer logicDefectCount;
/**
* UI交互类型缺陷数
*/
private Integer uiDefectCount;
/**
* 性能问题类型缺陷数
*/
private Integer performanceDefectCount;
/**
* 兼容性问题类型缺陷数
*/
private Integer compatibilityDefectCount;
/**
* 配置错误类型缺陷数
*/
private Integer configurationDefectCount;
/**
* 安全问题类型缺陷数
*/
private Integer securityDefectCount;
/**
* 安装部署类型缺陷数
*/
private Integer installationDefectCount;
/**
* 其他类型缺陷数
*/
private Integer otherDefectCount;
/**
* 用例执行时间
*/
private List<String> caseTrendDates;
}

View File

@@ -0,0 +1,52 @@
package com.test.test.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.test.common.core.domain.BaseEntity;
import java.util.Date;
import lombok.Data;
/**
* 测试计划关联需求VO
*/
@Data
public class TestPlanProjectVo extends BaseEntity {
private static final long serialVersionUID = 2482748159724585467L;
/** 需求编码 */
private String serialNumber;
/** 需求名称 */
private String name;
/** 需求概要 */
private String outline;
/** 需求描述 */
private String detail;
/** 优先级(p0,p1,p2,p3,p4) */
private String priority;
/** 预计完成时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
private Date estimatedTime;
/** 需求来源(0,产品经理,1,客户) */
private String source;
/** 需求类型(0,优化,1,新功能) */
private String type;
/** 状态(0,未开始,1,进行中,2,已完成,3,已终止) */
private String status;
/** 负责人 */
private String manager;
/** 版本 */
private String version;
/** 0,正常,1,删除 */
private String delFlag;
}

View File

@@ -0,0 +1,32 @@
package com.test.test.domain.vo;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
@Data
public class TestReportVo extends BaseEntity {
private static final long serialVersionUID = -4331077290310280474L;
/** 测试报告id */
private Long id;
/**
* 测试报告名称
*/
private String name;
/** 测试结果(0,未通过,1,通过) */
private String result;
/** 测试报告jason格式存储*/
private String report;
/** 测试用例类型(0,冒烟测试,1,功能测试,2,回归测试,3,准生产测试,4,生产验证) */
private Long type;
/** 测试报告发送状态0,未发送,1,已发送) */
@Excel(name = "测试报告发送状态", readConverterExp = "0=,未发送,1,已发送")
private String status;
}

View File

@@ -0,0 +1,50 @@
package com.test.test.domain.vo;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.ArrayList;
import java.util.List;
/**
* ui自动化对象 ui_automation
*
* @author test
* @date 2025-04-22
*/
@Data
public class UiAutomationVO
{
private static final long serialVersionUID = 1L;
/** $column.columnComment */
private Long id;
/** 模块id */
private Long groupId;
/** 场景名称 */
private String name;
/** 用例等级 */
private String caseLevel;
/** 状态 未开始 进行中 已完成 */
private String status;
/** 标签 */
private String label;
/** 责任人 */
private String dutyBy;
/**描述*/
private String description;
/**场景步骤*/
private List<UiSceneStepsVO> uiSceneStepsVOList = new ArrayList<>();
}

View File

@@ -0,0 +1,56 @@
package com.test.test.domain.vo;
import com.test.test.domain.qo.AssertionConfigQO;
import com.test.test.domain.qo.AssertionQO;
import com.test.test.domain.qo.DataExtractionConfigQO;
import com.test.test.domain.qo.OtherSettingsQO;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* ui高级设置对象 ui_high_setting
*
* @author test
* @date 2025-04-23
*/
@Data
public class UiHighSettingVO
{
private static final long serialVersionUID = 1L;
/** 场景步骤id */
private Long sceneStepsId;
/** 设置类型 */
private String settingType;
/** 名称 */
private String name;
/** 操作类型 */
private String operateType;
/** 等待时间 */
private String awateTime;
/** 错误处理 */
private String errorHandling;
/** 设置顺序 */
private Integer orderNumber;
/** 是否禁用 */
private Integer isDisabled;
/**断言*/
private AssertionConfigQO assertionQOList = new AssertionConfigQO();
/**数据提取*/
private DataExtractionConfigQO dataExtractionQOList =new DataExtractionConfigQO();
/**其他设置*/
private OtherSettingsQO otherSettingsQO;
}

View File

@@ -0,0 +1,69 @@
package com.test.test.domain.vo;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.ArrayList;
import java.util.List;
/**
* ui报告对象 ui_report
*
* @author test
* @date 2025-04-24
*/
@Data
public class UiReportVO extends BaseEntity
{
/** $column.columnComment */
private Long id;
/** 名称 */
private String name;
/** 耗时 */
private String take;
/** 失败率 */
private String faiiRate;
/** 成功断言 */
private String successAssertion;
/** 场景数 */
private Integer scenesNumber;
/** 场景成功数 */
private Integer scenesSucceedNumber;
/** 场景失败数 */
private Integer scenesErrorNumber;
/** 场景未执行数 */
private Integer scenesNotNumber;
/** 步骤数 */
private Integer stepsNumber;
/** 步骤成功数 */
private Integer stepsSucceedNumber;
/** 步骤失败数 */
private Integer stepsErrorNumber;
/** 步骤未执行数 */
private Integer stepsNotNumber;
/**报告步骤全部详情*/
private List<UiSceneStepsReportVO> uiSceneStepsAllReportVOList = new ArrayList<>() ;
/**报告步骤失败详情*/
private List<UiSceneStepsReportVO> uiSceneStepsErrorReportVOList = new ArrayList<>() ;
/**报告步骤未执行详情*/
private List<UiSceneStepsReportVO> uiSceneStepsNotReportVOList = new ArrayList<>() ;
/**控制台信息*/
private String consoleStr;
}

View File

@@ -0,0 +1,48 @@
package com.test.test.domain.vo;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* ui自动化场景报告对象 ui_scene_steps_report
*
* @author test
* @date 2025-04-24
*/
@Data
public class UiSceneStepsReportVO
{
/** 报告id */
private Long reportId;
/** 名称 */
private String name;
/** 日志 */
private String logInfo;
/** 执行类型 1成功 0未执行 2执行失败 */
private String executionFlag;
/** 耗时 */
private String take;
/** 截图 */
private String screenshot;
/** 断言json */
private String assertionJson;
/** 数据提取json */
private String extractionDataJson;
/** 场景步骤序号 */
private Integer orderNumber;
}

View File

@@ -0,0 +1,104 @@
package com.test.test.domain.vo;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import jdk.jfr.DataAmount;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.ArrayList;
import java.util.List;
/**
* ui自动化场景步骤对象 ui_scene_steps
*
* @author test
* @date 2025-04-23
*/
@Data
public class UiSceneStepsVO
{
private Long automationId;
/** 操作类型 */
private String operateType;
/** 名称 */
private String name;
/** 步骤类型 */
private String stepType;
/** url */
private String url;
/** 是否追加页面 */
private Integer isAppendPage;
/** 操作 */
private Integer operate;
/** 操作对象 */
private String operateObject;
/** 元素库名称 */
private Long operateGroupId;
/** 元素id */
private Long operateElementId;
/** 元素定位类型 */
private String operateLocType;
/** 元素定位值 */
private String operateLocValue;
/** 点击方式 */
private String clickMethod;
/** 输入内容 */
private String inputValue;
/** 窗口尺寸 */
private Integer windowSize;
/** 子选项 */
private String subOptions;
/** 子选项值 */
private String subOptionsValue;
/** 等待值 */
private String awaitValue;
/** 是否禁用 */
private Integer isDisabled;
/** 是否删除 */
private Integer delFlag;
/** 场景步骤序号 */
private Integer orderNumber;
/** 句柄id */
private String handleId;
/** 网页索引号 */
private Integer pageIndex;
/** frame索引号 */
private Integer frameIndex;
/**是否输入*/
private String isEnter;
/**操作方式*/
private String operateWay;
/**高级设置*/
private List<UiHighSettingVO> uiHighSettingVOList = new ArrayList<>();
}

View File

@@ -0,0 +1,62 @@
package com.test.test.mapper;
import com.test.test.domain.PerformanceTestCase;
import java.util.List;
/**
* 性能测试与测试用例关联Mapper接口
*
* @author test
* @date 2025-04-14
*/
public interface PerformanceTestCaseMapper
{
/**
* 查询性能测试与测试用例关联
*
* @param id 性能测试与测试用例关联主键
* @return 性能测试与测试用例关联
*/
public PerformanceTestCase selectPerformanceTestCaseById(Long id);
/**
* 查询性能测试与测试用例关联列表
*
* @param performanceTestCase 性能测试与测试用例关联
* @return 性能测试与测试用例关联集合
*/
public List<PerformanceTestCase> selectPerformanceTestCaseList(PerformanceTestCase performanceTestCase);
/**
* 新增性能测试与测试用例关联
*
* @param performanceTestCase 性能测试与测试用例关联
* @return 结果
*/
public int insertPerformanceTestCase(PerformanceTestCase performanceTestCase);
/**
* 修改性能测试与测试用例关联
*
* @param performanceTestCase 性能测试与测试用例关联
* @return 结果
*/
public int updatePerformanceTestCase(PerformanceTestCase performanceTestCase);
/**
* 删除性能测试与测试用例关联
*
* @param id 性能测试与测试用例关联主键
* @return 结果
*/
public int deletePerformanceTestCaseById(Long id);
/**
* 批量删除性能测试与测试用例关联
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deletePerformanceTestCaseByIds(Long[] ids);
}

View File

@@ -0,0 +1,62 @@
package com.test.test.mapper;
import com.test.test.domain.PerformanceTestCaseReport;
import java.util.List;
/**
* 性能测试用例报告Mapper接口
*
* @author test
* @date 2025-04-14
*/
public interface PerformanceTestCaseReportMapper
{
/**
* 查询性能测试用例报告
*
* @param id 性能测试用例报告主键
* @return 性能测试用例报告
*/
public PerformanceTestCaseReport selectPerformanceTestCaseReportById(Long id);
/**
* 查询性能测试用例报告列表
*
* @param performanceTestCaseReport 性能测试用例报告
* @return 性能测试用例报告集合
*/
public List<PerformanceTestCaseReport> selectPerformanceTestCaseReportList(PerformanceTestCaseReport performanceTestCaseReport);
/**
* 新增性能测试用例报告
*
* @param performanceTestCaseReport 性能测试用例报告
* @return 结果
*/
public int insertPerformanceTestCaseReport(PerformanceTestCaseReport performanceTestCaseReport);
/**
* 修改性能测试用例报告
*
* @param performanceTestCaseReport 性能测试用例报告
* @return 结果
*/
public int updatePerformanceTestCaseReport(PerformanceTestCaseReport performanceTestCaseReport);
/**
* 删除性能测试用例报告
*
* @param id 性能测试用例报告主键
* @return 结果
*/
public int deletePerformanceTestCaseReportById(Long id);
/**
* 批量删除性能测试用例报告
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deletePerformanceTestCaseReportByIds(Long[] ids);
}

View File

@@ -0,0 +1,62 @@
package com.test.test.mapper;
import com.test.test.domain.PerformanceTest;
import java.util.List;
/**
* 性能测试Mapper接口
*
* @author test
* @date 2025-04-14
*/
public interface PerformanceTestMapper
{
/**
* 查询性能测试
*
* @param id 性能测试主键
* @return 性能测试
*/
public PerformanceTest selectPerformanceTestById(Long id);
/**
* 查询性能测试列表
*
* @param performanceTest 性能测试
* @return 性能测试集合
*/
public List<PerformanceTest> selectPerformanceTestList(PerformanceTest performanceTest);
/**
* 新增性能测试
*
* @param performanceTest 性能测试
* @return 结果
*/
public int insertPerformanceTest(PerformanceTest performanceTest);
/**
* 修改性能测试
*
* @param performanceTest 性能测试
* @return 结果
*/
public int updatePerformanceTest(PerformanceTest performanceTest);
/**
* 删除性能测试
*
* @param id 性能测试主键
* @return 结果
*/
public int deletePerformanceTestById(Long id);
/**
* 批量删除性能测试
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deletePerformanceTestByIds(Long[] ids);
}

View File

@@ -2,6 +2,7 @@ package com.test.test.mapper;
import com.test.test.domain.TestCaseLog;
import com.test.test.domain.qo.TestReportAddQO;
import java.util.List;
/**
@@ -28,6 +29,14 @@ public interface TestCaseLogMapper
*/
public List<TestCaseLog> selectTestCaseLogList(TestCaseLog testCaseLog);
/**
* 查询用例日志列表
*
* @param testCaseLog 用例日志
* @return 用例日志集合
*/
public String selectTestCaseLogCaseSid(TestReportAddQO testCaseLog);
/**
* 新增用例日志
*

View File

@@ -1,6 +1,7 @@
package com.test.test.mapper;
import com.test.test.domain.TestCase;
import com.test.test.domain.TestDefect;
import com.test.test.domain.qo.TestCaseListQO;
import java.util.List;
@@ -20,6 +21,16 @@ public interface TestCaseMapper
*/
List<TestCase> selectTestCaseList(TestCaseListQO qo);
/**
* 查询测试计划可关联的用例列表
*/
List<TestCase> selectValidTestPlanCaseList(TestCaseListQO qo);
/**
* 查询用例列表
*/
List<TestCase> selectTestCaseListNoGroupId(TestCase testCase);
/**
* 新增用例
*/
@@ -39,4 +50,9 @@ public interface TestCaseMapper
* 批量删除用例
*/
int deleteTestCaseByIds(Long[] ids);
/**
* 查询关联的用例列表
*/
List<TestCase> selectRelateCaseList(Long projectId);
}

View File

@@ -0,0 +1,68 @@
package com.test.test.mapper;
import com.test.test.domain.TestDefect;
import com.test.test.domain.qo.TestDefectListQO;
import java.util.List;
/**
* 测试缺陷Mapper接口
*
* @author test
* @date 2025-04-22
*/
public interface TestDefectMapper
{
/**
* 查询测试缺陷
*
* @param id 测试缺陷主键
* @return 测试缺陷
*/
public TestDefect selectTestDefectById(Long id);
/**
* 查询测试缺陷列表
*
* @param qo 测试缺陷
* @return 测试缺陷集合
*/
public List<TestDefect> selectTestDefectList(TestDefectListQO qo);
/**
* 新增测试缺陷
*
* @param testDefect 测试缺陷
* @return 结果
*/
public int insertTestDefect(TestDefect testDefect);
/**
* 修改测试缺陷
*
* @param testDefect 测试缺陷
* @return 结果
*/
public int updateTestDefect(TestDefect testDefect);
/**
* 删除测试缺陷
*
* @param id 测试缺陷主键
* @return 结果
*/
public int deleteTestDefectById(Long id);
/**
* 批量删除测试缺陷
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteTestDefectByIds(Long[] ids);
/**
* 查询关联的缺陷列表
*/
List<TestDefect> selectRelateDefectList(Long projectId);
}

View File

@@ -13,6 +13,11 @@ public interface TestGroupMapper
*/
List<TestGroup> selectTestGroupList(String type);
/**
* 查询节点(文件夹)列表
*/
TestGroup selectTestGroupById(Long id);
/**
* 查询节点(文件夹)列表
*/

Some files were not shown because too many files have changed in this diff Show More