feat(接口测试): 场景列表总执行通过率计算

https://www.tapd.cn/55049933/bugtrace/bugs/view/1155049933001048522
This commit is contained in:
Jianguo-Genius 2024-11-07 16:28:03 +08:00 committed by 建国
parent f8ef042a62
commit 6657ad923f
9 changed files with 102 additions and 1 deletions

View File

@ -0,0 +1,22 @@
package io.metersphere.sdk.util;
import java.text.DecimalFormat;
public class CalculateUtils {
// 报告所需的百分比计算
public static String reportPercentage(int numerator, int denominator) {
DecimalFormat rateFormat = new DecimalFormat("#0.00");
rateFormat.setMinimumFractionDigits(2);
rateFormat.setMaximumFractionDigits(2);
double passRate = Double.parseDouble(rateFormat.format((double) numerator * 100 / (double) denominator));
if (passRate == 100 && numerator < denominator) {
return "99.99%";
} else if (passRate == 0 && numerator > 0) {
return "0.01%";
} else {
return passRate + "%";
}
}
}

View File

@ -35,6 +35,8 @@ import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager; import io.metersphere.system.utils.Pager;
import io.metersphere.system.utils.SessionUtils; import io.metersphere.system.utils.SessionUtils;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@ -74,6 +76,14 @@ public class ApiScenarioController {
return PageUtils.setPageInfo(page, apiScenarioService.getScenarioPage(request, true, null)); return PageUtils.setPageInfo(page, apiScenarioService.getScenarioPage(request, true, null));
} }
@PostMapping("/statistics")
@Operation(summary = "接口测试-接口场景管理-获取通过率")
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ)
@Parameter(name = "ids", description = "场景id集合", schema = @Schema(requiredMode = Schema.RequiredMode.REQUIRED))
public List<ApiScenarioDTO> selectTestPlanMetricById(@RequestBody List<String> ids) {
return apiScenarioService.calculateRate(ids);
}
@PostMapping("/trash/page") @PostMapping("/trash/page")
@Operation(summary = "接口测试-接口场景管理-场景列表(deleted 状态为 1 时为回收站数据)") @Operation(summary = "接口测试-接口场景管理-场景列表(deleted 状态为 1 时为回收站数据)")
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ) @RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ)

View File

@ -0,0 +1,11 @@
package io.metersphere.api.dto;
import lombok.Data;
@Data
public class ApiExecResultDTO {
// 接口定义接口用例场景等的id
private String resourceId;
private String execResult;
}

View File

@ -28,4 +28,6 @@ public class ApiScenarioDTO extends ApiScenario {
private Long nextTriggerTime; private Long nextTriggerTime;
@Schema(description = "脚本错误标识") @Schema(description = "脚本错误标识")
private String scriptIdentifier; private String scriptIdentifier;
@Schema(description = "执行通过率", requiredMode = Schema.RequiredMode.REQUIRED)
private String execPassRate = "0%";
} }

View File

@ -2,6 +2,7 @@ package io.metersphere.api.mapper;
import io.metersphere.api.domain.ApiScenarioBlob; import io.metersphere.api.domain.ApiScenarioBlob;
import io.metersphere.api.domain.ApiScenarioReport; import io.metersphere.api.domain.ApiScenarioReport;
import io.metersphere.api.dto.ApiExecResultDTO;
import io.metersphere.api.dto.definition.ApiReportBatchRequest; import io.metersphere.api.dto.definition.ApiReportBatchRequest;
import io.metersphere.api.dto.definition.ApiReportPageRequest; import io.metersphere.api.dto.definition.ApiReportPageRequest;
import io.metersphere.api.dto.definition.ExecuteReportDTO; import io.metersphere.api.dto.definition.ExecuteReportDTO;
@ -62,4 +63,6 @@ public interface ExtApiScenarioReportMapper {
List<ExecuteReportDTO> getHistoryDeleted(@Param("ids") List<String> ids); List<ExecuteReportDTO> getHistoryDeleted(@Param("ids") List<String> ids);
List<ExecuteReportDTO> getTestPlanNum(@Param("ids") List<String> ids); List<ExecuteReportDTO> getTestPlanNum(@Param("ids") List<String> ids);
List<ApiExecResultDTO> selectExecResultByScenarioIds(@Param("ids") List<String> scenarioIds);
} }

View File

@ -273,6 +273,15 @@
</foreach> </foreach>
</if> </if>
</select> </select>
<select id="selectExecResultByScenarioIds" resultType="io.metersphere.api.dto.ApiExecResultDTO">
select record.api_scenario_id AS resourceId,report.status AS execResult
from api_scenario_record record
inner join api_scenario_report report on record.api_scenario_report_id = report.id
where record.api_scenario_id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<sql id="filters"> <sql id="filters">
<if test="${filter} != null and ${filter}.size() > 0"> <if test="${filter} != null and ${filter}.size() > 0">

View File

@ -2619,4 +2619,32 @@ public class ApiScenarioService extends MoveNodeService {
} }
} }
} }
// 场景统计相关
public List<ApiScenarioDTO> calculateRate(List<String> ids) {
List<ApiScenarioDTO> result = new ArrayList<>();
if (CollectionUtils.isNotEmpty(ids)) {
List<ApiExecResultDTO> scenarioExecResult = extApiScenarioReportMapper.selectExecResultByScenarioIds(ids);
Map<String, List<ApiExecResultDTO>> scenarioReportMap = scenarioExecResult.stream().collect(Collectors.groupingBy(ApiExecResultDTO::getResourceId));
for (String scenarioId : ids) {
ApiScenarioDTO dto = new ApiScenarioDTO();
dto.setId(scenarioId);
List<ApiExecResultDTO> execResultDTOs = scenarioReportMap.get(scenarioId);
if (CollectionUtils.isNotEmpty(execResultDTOs)) {
int all = execResultDTOs.size();
int passCount = 0;
for (ApiExecResultDTO execResultDTO : execResultDTOs) {
if (StringUtils.equals(execResultDTO.getExecResult(), ResultStatus.SUCCESS.name())) {
passCount++;
}
}
dto.setExecPassRate(CalculateUtils.reportPercentage(passCount, all));
}
result.add(dto);
}
}
return result;
}
} }

View File

@ -100,6 +100,8 @@ public class ApiScenarioControllerTests extends BaseTest {
private static final String BASE_PATH = "/api/scenario/"; private static final String BASE_PATH = "/api/scenario/";
private static final String TRASH_PAGE = "trash/page"; private static final String TRASH_PAGE = "trash/page";
private static final String BATCH_EDIT = "batch-operation/edit"; private static final String BATCH_EDIT = "batch-operation/edit";
private static final String STATISTICS = "/statistics";
private static final String FOLLOW = "follow/"; private static final String FOLLOW = "follow/";
protected static final String UPLOAD_TEMP_FILE = "upload/temp/file"; protected static final String UPLOAD_TEMP_FILE = "upload/temp/file";
protected static final String DELETE_TO_GC = "delete-to-gc/{0}"; protected static final String DELETE_TO_GC = "delete-to-gc/{0}";
@ -1458,6 +1460,10 @@ public class ApiScenarioControllerTests extends BaseTest {
//返回的数据量不超过规定要返回的数据量相同 //返回的数据量不超过规定要返回的数据量相同
Assertions.assertTrue(((List<ApiScenarioDTO>) returnPager.getList()).size() <= pageRequest.getPageSize()); Assertions.assertTrue(((List<ApiScenarioDTO>) returnPager.getList()).size() <= pageRequest.getPageSize());
// 查统计数据
List<String> apiScenarioIds = Collections.singletonList("api-scenario-id1");
requestPostWithOk(STATISTICS, apiScenarioIds);
//查询api-scenario-id1的数据 //查询api-scenario-id1的数据
pageRequest.setScenarioId("api-scenario-id1"); pageRequest.setScenarioId("api-scenario-id1");
mvcResult = requestPostAndReturn(DEFAULT_PAGE, pageRequest); mvcResult = requestPostAndReturn(DEFAULT_PAGE, pageRequest);

View File

@ -29,6 +29,7 @@ import io.metersphere.sdk.domain.ShareInfo;
import io.metersphere.sdk.mapper.EnvironmentGroupMapper; import io.metersphere.sdk.mapper.EnvironmentGroupMapper;
import io.metersphere.sdk.mapper.EnvironmentMapper; import io.metersphere.sdk.mapper.EnvironmentMapper;
import io.metersphere.sdk.mapper.ShareInfoMapper; import io.metersphere.sdk.mapper.ShareInfoMapper;
import io.metersphere.sdk.util.CalculateUtils;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest; import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder; import io.metersphere.system.controller.handler.ResultHolder;
@ -50,6 +51,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -97,7 +99,7 @@ public class ApiScenarioReportControllerTests extends BaseTest {
@Test @Test
@Order(1) @Order(1)
public void testInsert() { public void testInsert() throws Exception {
List<ApiScenarioReport> reports = new ArrayList<>(); List<ApiScenarioReport> reports = new ArrayList<>();
List<ApiScenarioRecord> records = new ArrayList<>(); List<ApiScenarioRecord> records = new ArrayList<>();
for (int i = 0; i < 2515; i++) { for (int i = 0; i < 2515; i++) {
@ -192,6 +194,14 @@ public class ApiScenarioReportControllerTests extends BaseTest {
//校验权限 //校验权限
requestPostPermissionTest(PermissionConstants.PROJECT_API_REPORT_READ, PAGE, request); requestPostPermissionTest(PermissionConstants.PROJECT_API_REPORT_READ, PAGE, request);
// 顺便查找一下通过率
// 查统计数据
List<String> apiScenarioIds = Collections.singletonList("scenario-record-id0");
requestPostWithOk("/api/scenario/statistics", apiScenarioIds);
Assertions.assertEquals(CalculateUtils.reportPercentage(1, 999999999), "0.01%");
Assertions.assertEquals(CalculateUtils.reportPercentage(999999998, 999999999), "99.99%");
Assertions.assertNotEquals(CalculateUtils.reportPercentage(499999998, 999999999), "100%");
} }
@Override @Override