feat(接口测试): 报告增加统计指标

This commit is contained in:
fit2-zhao 2024-01-17 11:37:34 +08:00 committed by Craftsman
parent cce42065d7
commit 6c6edd4e44
7 changed files with 69 additions and 145 deletions

View File

@ -0,0 +1,5 @@
package io.metersphere.sdk.constants;
public enum ProcessDataStatus {
MS_RESOURCE_ID, MS_STEP_ID, MS_FAKE_ERROR
}

View File

@ -6,15 +6,18 @@ import lombok.Data;
public class ProcessResultDTO { public class ProcessResultDTO {
// 报告状态 // 报告状态
private String status; private String status;
// 总数
// TODO 总数,放报告生成后计算
private long total; private long total;
// 成功总数 // 成功总数
private long successCount; private long successCount;
// 误报总数 // 误报总数
private long fakeErrorCount; private long fakeErrorCount;
// 失败总数 // 失败总数
private long errorCount; private long errorCount;
// 未执行总数
// TODO 根据初始步骤大小在执行过程中进行标记 初始大小 - 过程标记步骤
private long pendingCount; private long pendingCount;
// 断言总数 // 断言总数
private long assertionCount; private long assertionCount;
@ -28,7 +31,7 @@ public class ProcessResultDTO {
private String assertionPassRate; private String assertionPassRate;
public void computerTotal() { public void computerTotal() {
this.total = (this.successCount + this.errorCount + this.pendingCount); this.total = this.pendingCount + this.errorCount + this.successCount;
} }
public void computerFakeError(long fakeErrorCount) { public void computerFakeError(long fakeErrorCount) {
@ -43,10 +46,6 @@ public class ProcessResultDTO {
this.errorCount += error; this.errorCount += error;
} }
public void computerPending(long pending) {
this.pendingCount += pending;
}
public void computerAssertion(long assertion) { public void computerAssertion(long assertion) {
this.assertionCount += assertion; this.assertionCount += assertion;
} }
@ -55,19 +54,35 @@ public class ProcessResultDTO {
this.successAssertionCount += successAssertion; this.successAssertionCount += successAssertion;
} }
/**
* 整体执行完成后调用计算执行率
* (成功+失败 ) /总量* 100
*/
public void computerRequestExecutionRate() { public void computerRequestExecutionRate() {
this.computerTotal(); long count = this.successCount + this.errorCount;
double executionRate = (double) this.total / (this.successCount + this.errorCount); if (this.total > 0 && count > 0) {
double executionRate = (double) count / this.total * 100;
this.requestExecutionRate = String.format("%.2f", executionRate); this.requestExecutionRate = String.format("%.2f", executionRate);
} }
public void computerRequestPassRate() {
this.computerTotal();
this.requestPassRate = String.format("%.2f", (double) this.total / (this.successCount));
} }
/**
* 整体完成后调用计算通过率
* 成功总数 / 总量 * 100
*/
public void computerRequestPassRate() {
if (this.total > 0 && this.successCount > 0) {
this.requestPassRate = String.format("%.2f", (double) this.successCount / this.total * 100);
}
}
/**
* 整体完成后调用计算断言通过率
*/
public void computerAssertionPassRate() { public void computerAssertionPassRate() {
this.assertionPassRate = String.format("%.2f", (double) this.assertionCount / successAssertionCount); if (this.assertionCount > 0 && successAssertionCount > 0) {
this.assertionPassRate = String.format("%.2f", (double) successAssertionCount / this.assertionCount * 100);
}
} }
} }

View File

@ -11,10 +11,10 @@ import java.util.List;
@Data @Data
public class RequestResult { public class RequestResult {
// 请求ID // 请求ID
private String id; private String resourceId;
// 步骤请求唯一ID // 步骤请求唯一ID
private String resourceId; private String stepId;
// 线程名称 // 线程名称
private String threadName; private String threadName;

View File

@ -1,6 +1,6 @@
package io.metersphere.sdk.dto.api.result; package io.metersphere.sdk.dto.api.result;
import io.metersphere.sdk.dto.api.CollectionReportDTO; import io.metersphere.sdk.dto.api.task.TaskRequest;
import lombok.Data; import lombok.Data;
import java.io.Serial; import java.io.Serial;
@ -13,40 +13,29 @@ public class TaskResult implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
// TODO: 补充任务执行结果数据结构
private List<RequestResult> requestResults;
private String runMode;
private String queueId;
private String reportId;
private String reportType;
private String testPlanReportId;
private String testId;
private String runType;
private String console;
private String runningDebugSampler;
private Boolean hasEnded;
private boolean retryEnable;
/** /**
* 项目id * 任务执行结果数据结构
*/ */
private String projectId; private List<RequestResult> requestResults;
/**
* 控制台信息
*/
private String console;
/**
* debug 信息
*/
private String runningDebugSampler;
/**
* 线程组执行完成标识
*/
private Boolean hasEnded;
/** /**
* 执行过程状态 * 执行过程状态
*/ */
private ProcessResultDTO processResultDTO; private ProcessResultDTO processResultDTO;
/**
* 资源类型
* ApiResourceType
*/
private String resourceType;
/**
* 环境变量处理信息
*/
String environmentId;
/** /**
* 集合报告,空则是单报告 * 请求参数
*/ */
private CollectionReportDTO collectionReport; private TaskRequest request;
} }

View File

@ -36,6 +36,13 @@ public class TaskRequest implements Serializable {
* 执行模式 * 执行模式
*/ */
private String runMode; private String runMode;
/**
* 触发方式
* 手动执行批量执行API执行定时任务
*/
private String triggerMode;
/** /**
* 资源类型 * 资源类型
* ApiResourceType * ApiResourceType
@ -74,5 +81,10 @@ public class TaskRequest implements Serializable {
*/ */
private CollectionReportDTO collectionReport; private CollectionReportDTO collectionReport;
/**
* 要执行的请求总量
*/
private Long requestCount;
// TODO 其它执行参数 // TODO 其它执行参数
} }

View File

@ -1,102 +0,0 @@
package io.metersphere.sdk.util;
import io.metersphere.sdk.constants.ApiReportStatus;
import io.metersphere.sdk.dto.api.result.ProcessResultDTO;
import io.metersphere.sdk.dto.api.result.RequestResult;
import io.metersphere.sdk.dto.api.result.TaskResult;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class ReportStatusUtils {
public static List<RequestResult> filterRetryResults(List<RequestResult> results) {
List<RequestResult> list = new LinkedList<>();
if (CollectionUtils.isNotEmpty(results)) {
Map<String, List<RequestResult>> resultMap = results.stream().collect(Collectors.groupingBy(RequestResult::getResourceId));
resultMap.forEach((k, v) -> {
if (CollectionUtils.isNotEmpty(v)) {
// 校验是否含重试结果
List<RequestResult> isRetryResults = v.stream().filter(c ->
StringUtils.isNotEmpty(c.getName()) && c.getName().startsWith(RetryResultUtils.RETRY_CN))
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(isRetryResults)) {
list.add(isRetryResults.getLast());
} else {
// 成功的结果
list.addAll(v);
}
}
});
}
return list;
}
/**
* 返回正确的报告状态
*
* @param dto jmeter返回
*/
public static ProcessResultDTO getStatus(TaskResult dto, ProcessResultDTO process) {
process.computerSuccess(dto.getRequestResults().stream()
.filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ApiReportStatus.SUCCESS.name())).count());
process.computerFakeError(dto.getRequestResults().stream()
.filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ApiReportStatus.FAKE_ERROR.name())).count());
process.computerError(dto.getRequestResults().stream()
.filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ApiReportStatus.ERROR.name())).count());
process.computerPending(dto.getRequestResults().stream()
.filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ApiReportStatus.PENDING.name())).count());
// 断言计算
dto.getRequestResults().forEach(requestResult -> {
process.computerAssertion(requestResult.getAssertionTotal());
process.computerSuccessAssertion(requestResult.getPassAssertionsTotal());
});
// 各种通过率
process.computerRequestExecutionRate();
process.computerRequestPassRate();
process.computerAssertionPassRate();
if (StringUtils.equals(process.getStatus(), ApiReportStatus.ERROR.name())) {
return process;
}
if (ObjectUtils.isNotEmpty(dto.getProcessResultDTO())) {
// 资源池执行整体传输失败单条传输内容获取资源池执行统计的状态
process.setStatus(dto.getProcessResultDTO().getStatus());
}
// 过滤掉重试结果后进行统计
long errorSize = process.getErrorCount();
// 误报
long errorReportResultSize = process.getFakeErrorCount();
// 默认状态
String status = dto.getRequestResults().isEmpty() && StringUtils.isEmpty(process.getStatus())
? ApiReportStatus.PENDING.name()
: StringUtils.defaultIfEmpty(process.getStatus(), ApiReportStatus.SUCCESS.name());
if (errorSize > 0) {
status = ApiReportStatus.ERROR.name();
} else if (errorReportResultSize > 0) {
status = ApiReportStatus.FAKE_ERROR.name();
}
process.setStatus(status);
process.computerTotal();
return process;
}
public static ProcessResultDTO computedProcess(TaskResult dto) {
ProcessResultDTO result = dto.getProcessResultDTO();
result = getStatus(dto, result);
if (result.getTotal() > 0 && result.getTotal() == result.getSuccessCount()) {
result.setStatus(ApiReportStatus.SUCCESS.name());
}
return result;
}
}

View File

@ -9,6 +9,7 @@ import io.metersphere.api.parser.jmeter.body.MsFormDataBodyConverter;
import io.metersphere.api.parser.jmeter.body.MsWWWFormBodyConverter; import io.metersphere.api.parser.jmeter.body.MsWWWFormBodyConverter;
import io.metersphere.plugin.api.dto.ParameterConfig; import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.plugin.api.spi.AbstractJmeterElementConverter; import io.metersphere.plugin.api.spi.AbstractJmeterElementConverter;
import io.metersphere.sdk.constants.ProcessDataStatus;
import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.LogUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -42,6 +43,10 @@ public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTT
sampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName()); sampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(HTTP_TEST_SAMPLE_GUI)); sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(HTTP_TEST_SAMPLE_GUI));
// TODO: 当前步骤唯一标识很重要结果和步骤匹配的关键
sampler.setProperty(ProcessDataStatus.MS_RESOURCE_ID.name(), msHTTPElement.getResourceId());
sampler.setProperty(ProcessDataStatus.MS_STEP_ID.name(), msHTTPElement.getStepId());
sampler.setMethod(msHTTPElement.getMethod()); sampler.setMethod(msHTTPElement.getMethod());
// todo 根据环境设置 // todo 根据环境设置
sampler.setDomain(msHTTPElement.getUrl()); sampler.setDomain(msHTTPElement.getUrl());