refactor(接口测试): 优化执行列表

This commit is contained in:
wxg0103 2024-06-11 16:25:02 +08:00 committed by 刘瑞斌
parent 84fcbc8aff
commit 49345ac62a
16 changed files with 172 additions and 14 deletions

View File

@ -545,3 +545,5 @@ global_request_header=全局请求头
url_format_error=请检查Swagger URL是否输入正确
swagger_version_error=Swagger 版本不支持请检查是否为3.0版本!
test_plan=测试计划 ID

View File

@ -582,4 +582,6 @@ global_request_header=Global request header
url_format_error=Please check if the Swagger URL is entered correctly!
swagger_version_error=Swagger version not supported, please check if it is version 3.0!
swagger_version_error=Swagger version not supported, please check if it is version 3.0!
test_plan=Test Plan ID

View File

@ -578,4 +578,5 @@ current_user_can_not_operation_api_key=当前用户无操作该ApiKey的权限
global_request_header=全局请求头
url_format_error=请检查Swagger URL是否输入正确
swagger_version_error=Swagger 版本不支持请检查是否为3.0版本!
swagger_version_error=Swagger 版本不支持请检查是否为3.0版本!
test_plan=测试计划 ID

View File

@ -578,4 +578,5 @@ current_user_can_not_operation_api_key=當前用戶無法操作ApiKey
global_request_header=全局請求頭
url_format_error=请检查Swagger URL是否输入正确
swagger_version_error=Swagger 版本不支持请检查是否为3.0版本!
swagger_version_error=Swagger 版本不支持请检查是否为3.0版本!
test_plan=測試計劃 ID

View File

@ -26,7 +26,7 @@ public class ExecuteReportDTO implements Serializable {
@Schema(description = "报告结果/SUCCESS/ERROR")
private String status;
@Schema(description = "报告状态")
private String execStatus;
@ -42,6 +42,12 @@ public class ExecuteReportDTO implements Serializable {
@Schema(description = "是否集成")
private boolean integrated;
@Schema(description = "测试计划id")
private String testPlanId;
@Schema(description = "测试计划Num")
private String testPlanNum;
private static final long serialVersionUID = 1L;
}

View File

@ -500,7 +500,9 @@
api_scenario_report.create_user,
api_scenario_report.trigger_mode,
api_scenario_report.test_plan_scenario_id,
api_scenario_report.deleted
api_scenario_report.deleted,
api_scenario_report.integrated,
api_scenario_report.test_plan_scenario_id as test_plan_id
from api_scenario_report
left join api_scenario_record t1 on t1.api_scenario_report_id = api_scenario_report.id
where

View File

@ -57,4 +57,6 @@ public interface ExtApiScenarioReportMapper {
List<ExecuteReportDTO> getHistoryDeleted(@Param("ids") List<String> ids);
List<ExecuteReportDTO> getTestPlanNum(@Param("ids") List<String> ids);
}

View File

@ -254,6 +254,19 @@
</if>
</select>
<select id="getTestPlanNum" resultType="io.metersphere.api.dto.definition.ExecuteReportDTO">
select asr.id, test_plan.num as testPlanNum
from api_scenario_report asr
inner join test_plan_api_scenario tpas on asr.test_plan_scenario_id = tpas.id
inner join test_plan on tpas.test_plan_id = test_plan.id
<if test="ids != null and ids.size() > 0">
where asr.id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
</select>
<sql id="filters">
<if test="${filter} != null and ${filter}.size() > 0">
<foreach collection="${filter}.entrySet()" index="key" item="values">

View File

@ -75,22 +75,26 @@ public interface ExtApiTestCaseMapper {
DropNode selectNodeByPosOperator(NodeSortQueryParam nodeSortQueryParam);
List<ApiTestCase> getApiCaseExecuteInfoByIds(@Param("ids")List<String> ids);
List<ApiTestCase> getApiCaseExecuteInfoByIds(@Param("ids") List<String> ids);
/**
* 获取缺陷未关联的接口用例列表
*
* @param request provider参数
* @param deleted 是否删除状态
* @param sort 排序
* @param sort 排序
* @return 通用的列表Case集合
*/
List<TestCaseProviderDTO> listUnRelatedCaseWithBug(@Param("request") TestCasePageProviderRequest request, @Param("deleted") boolean deleted, @Param("sort") String sort);
/**
* 根据关联条件获取关联的用例ID
*
* @param request 关联参数
* @param deleted 是否删除状态
* @return 关联的用例ID集合
*/
List<String> getSelectIdsByAssociateParam(@Param("request")AssociateOtherCaseRequest request, @Param("deleted") boolean deleted);
List<String> getSelectIdsByAssociateParam(@Param("request") AssociateOtherCaseRequest request, @Param("deleted") boolean deleted);
List<ExecuteReportDTO> getTestPlanNum(@Param("ids") List<String> ids);
}

View File

@ -257,7 +257,8 @@
api_report.trigger_mode,
api_report.test_plan_case_id,
api_report.deleted,
api_report.integrated
api_report.integrated,
api_report.test_plan_case_id as test_plan_id
from api_report
left join api_test_case_record atc on atc.api_report_id = api_report.id
where
@ -390,6 +391,18 @@
)
<include refid="queryByAssociateParam"/>
</select>
<select id="getTestPlanNum" resultType="io.metersphere.api.dto.definition.ExecuteReportDTO">
select ar.id, test_plan.num as testPlanNum
from api_report ar
inner join test_plan_api_case tpac on ar.test_plan_case_id = tpac.id
inner join test_plan on tpac.test_plan_id = test_plan.id
<if test="ids != null and ids.size() > 0">
where ar.id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
</select>
<sql id="report_filters">
<if test="${filter} != null and ${filter}.size() > 0">

View File

@ -579,12 +579,26 @@ public class ApiTestCaseService extends MoveNodeService implements GetRunScriptS
List<ExecuteReportDTO> historyDeletedList = extApiReportMapper.getHistoryDeleted(reportIds);
historyDeletedMap = historyDeletedList.stream().collect(Collectors.toMap(ExecuteReportDTO::getId, Function.identity()));
}
Map<String, String> testPlanIdMap = executeList.stream()
.filter(apiReport -> !StringUtils.equals(apiReport.getTestPlanId(), "NONE"))
.collect(Collectors.toMap(ExecuteReportDTO::getId, ExecuteReportDTO::getTestPlanId));
List<String> testPlanIds = new ArrayList<>(testPlanIdMap.keySet());
Map<String, String> testPlanNumMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(testPlanIds)) {
List<ExecuteReportDTO> testPlanNameLists = extApiTestCaseMapper.getTestPlanNum(testPlanIds);
testPlanNumMap = testPlanNameLists.stream().collect(Collectors.toMap(ExecuteReportDTO::getId, ExecuteReportDTO::getTestPlanNum));
}
Map<String, ExecuteReportDTO> finalHistoryDeletedMap = historyDeletedMap;
Map<String, String> finalTestPlanNumMap = testPlanNumMap;
executeList.forEach(apiReport -> {
apiReport.setOperationUser(userMap.get(apiReport.getCreateUser()));
Date date = new Date(apiReport.getStartTime());
apiReport.setNum(sdf.format(date));
apiReport.setHistoryDeleted(MapUtils.isNotEmpty(finalHistoryDeletedMap) && !finalHistoryDeletedMap.containsKey(apiReport.getId()));
if (MapUtils.isNotEmpty(testPlanIdMap) && testPlanIdMap.containsKey(apiReport.getId())) {
apiReport.setTestPlanNum(StringUtils.join(Translator.get("test_plan"), ": ", finalTestPlanNumMap.get(apiReport.getId())));
}
});
return executeList;
}
@ -630,7 +644,7 @@ public class ApiTestCaseService extends MoveNodeService implements GetRunScriptS
return apiDefinitionExecuteInfo;
}
})
.filter(item -> item != null)
.filter(Objects::nonNull)
.toList();
}

View File

@ -2243,16 +2243,29 @@ public class ApiScenarioService extends MoveNodeService {
if (CollectionUtils.isNotEmpty(reportIds)) {
List<ExecuteReportDTO> historyDeletedList = extApiScenarioReportMapper.getHistoryDeleted(reportIds);
historyDeletedMap = historyDeletedList.stream().collect(Collectors.toMap(ExecuteReportDTO::getId, Function.identity()));
}
Map<String, String> testPlanIdMap = executeList.stream()
.filter(apiReport -> !StringUtils.equals(apiReport.getTestPlanId(), "NONE"))
.collect(Collectors.toMap(ExecuteReportDTO::getId, ExecuteReportDTO::getTestPlanId));
List<String> testPlanIds = new ArrayList<>(testPlanIdMap.keySet());
Map<String, String> testPlanNumMap = new HashMap<>();
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(testPlanIds)) {
List<ExecuteReportDTO> testPlanNameLists = extApiScenarioReportMapper.getTestPlanNum(testPlanIds);
testPlanNumMap = testPlanNameLists.stream().collect(Collectors.toMap(ExecuteReportDTO::getId, ExecuteReportDTO::getTestPlanNum));
}
Map<String, String> userMap = userLoginService.getUserNameMap(new ArrayList<>(userSet));
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Map<String, ExecuteReportDTO> finalHistoryDeletedMap = historyDeletedMap;
Map<String, String> finalTestPlanNumMap = testPlanNumMap;
executeList.forEach(apiReport -> {
apiReport.setOperationUser(userMap.get(apiReport.getCreateUser()));
Date date = new Date(apiReport.getStartTime());
apiReport.setNum(sdf.format(date));
apiReport.setHistoryDeleted(MapUtils.isNotEmpty(finalHistoryDeletedMap) && !finalHistoryDeletedMap.containsKey(apiReport.getId()));
if (MapUtils.isNotEmpty(testPlanIdMap) && testPlanIdMap.containsKey(apiReport.getId())) {
apiReport.setTestPlanNum(StringUtils.join(Translator.get("test_plan"), ": ", finalTestPlanNumMap.get(apiReport.getId())));
}
});
return executeList;
}

View File

@ -26,6 +26,10 @@ import io.metersphere.api.service.definition.ApiTestCaseService;
import io.metersphere.api.service.scenario.ApiScenarioReportService;
import io.metersphere.api.service.scenario.ApiScenarioService;
import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.plan.domain.TestPlanApiScenario;
import io.metersphere.plan.domain.TestPlanExample;
import io.metersphere.plan.mapper.TestPlanApiScenarioMapper;
import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.api.assertion.MsResponseCodeAssertion;
import io.metersphere.project.api.assertion.MsScriptAssertion;
@ -179,6 +183,10 @@ public class ApiScenarioControllerTests extends BaseTest {
private ApiScenarioReportService scenarioReportService;
@Resource
private ApiScenarioCsvStepMapper apiScenarioCsvStepMapper;
@Resource
private TestPlanMapper testPlanMapper;
@Resource
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
private static String fileMetadataId;
private static String fileMetadataStepId;
@ -2643,6 +2651,20 @@ public class ApiScenarioControllerTests extends BaseTest {
ApiScenario first = apiScenarioMapper.selectByExample(new ApiScenarioExample()).getFirst();
List<ApiScenarioReport> reports = new ArrayList<>();
List<ApiScenarioRecord> records = new ArrayList<>();
String planId = testPlanMapper.selectByExample(new TestPlanExample()).getFirst().getId();
TestPlanApiScenario testPlanApiScenario = new TestPlanApiScenario();
testPlanApiScenario.setTestPlanId(first.getId());
testPlanApiScenario.setId(IDGenerator.nextStr());
testPlanApiScenario.setApiScenarioId(first.getId());
testPlanApiScenario.setCreateUser("admin");
testPlanApiScenario.setCreateTime(System.currentTimeMillis());
testPlanApiScenario.setLastExecTime(System.currentTimeMillis());
testPlanApiScenario.setLastExecReportId(IDGenerator.nextStr());
testPlanApiScenario.setLastExecResult(ExecStatus.SUCCESS.name());
testPlanApiScenario.setPos(1024l);
testPlanApiScenario.setTestPlanCollectionId(planId);
testPlanApiScenarioMapper.insert(testPlanApiScenario);
for (int i = 0; i < 10; i++) {
ApiScenarioReport apiReport = new ApiScenarioReport();
apiReport.setId(IDGenerator.nextStr());
@ -2658,6 +2680,7 @@ public class ApiScenarioControllerTests extends BaseTest {
if (i % 2 == 0) {
apiReport.setStatus(ReportStatus.SUCCESS.name());
} else {
apiReport.setTestPlanScenarioId(testPlanApiScenario.getId());
apiReport.setStatus(ReportStatus.ERROR.name());
}
apiReport.setTriggerMode("api-trigger-mode" + i);

View File

@ -18,6 +18,10 @@ import io.metersphere.api.service.BaseFileManagementTestService;
import io.metersphere.api.service.definition.ApiReportService;
import io.metersphere.api.service.definition.ApiTestCaseService;
import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.plan.domain.TestPlanApiCase;
import io.metersphere.plan.domain.TestPlanExample;
import io.metersphere.plan.mapper.TestPlanApiCaseMapper;
import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.domain.ProjectVersion;
import io.metersphere.project.dto.environment.EnvironmentConfig;
@ -151,6 +155,10 @@ public class ApiTestCaseControllerTests extends BaseTest {
private ApiScenarioMapper apiScenarioMapper;
@Resource
private ApiScenarioStepMapper apiScenarioStepMapper;
@Resource
private TestPlanMapper testPlanMapper;
@Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper;
@Override
public String getBasePath() {
@ -770,6 +778,21 @@ public class ApiTestCaseControllerTests extends BaseTest {
ApiTestCase first = apiTestCaseMapper.selectByExample(new ApiTestCaseExample()).getFirst();
List<ApiReport> reports = new ArrayList<>();
List<ApiTestCaseRecord> records = new ArrayList<>();
String planId = testPlanMapper.selectByExample(new TestPlanExample()).getFirst().getId();
TestPlanApiCase testPlanApiCase = new TestPlanApiCase();
testPlanApiCase.setTestPlanId(first.getId());
testPlanApiCase.setId(IDGenerator.nextStr());
testPlanApiCase.setApiCaseId(first.getId());
testPlanApiCase.setCreateUser("admin");
testPlanApiCase.setCreateTime(System.currentTimeMillis());
testPlanApiCase.setLastExecTime(System.currentTimeMillis());
testPlanApiCase.setLastExecReportId(IDGenerator.nextStr());
testPlanApiCase.setLastExecResult(ExecStatus.SUCCESS.name());
testPlanApiCase.setPos(1024l);
testPlanApiCase.setTestPlanCollectionId(planId);
testPlanApiCaseMapper.insert(testPlanApiCase);
for (int i = 0; i < 10; i++) {
ApiReport apiReport = new ApiReport();
apiReport.setId(IDGenerator.nextStr());
@ -785,6 +808,7 @@ public class ApiTestCaseControllerTests extends BaseTest {
if (i % 2 == 0) {
apiReport.setStatus(ExecStatus.SUCCESS.name());
} else {
apiReport.setTestPlanCaseId(testPlanApiCase.getId());
apiReport.setStatus(ExecStatus.ERROR.name());
}
apiReport.setTriggerMode("api-trigger-mode" + i);

View File

@ -12,6 +12,23 @@
/>-->
</div>
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent">
<template #num="{ record }">
<div class="flex items-center justify-start">
<span type="text" class="px-0">{{ record.num }}</span>
<a-tooltip v-if="record.testPlanNum" :content="record.testPlanNum">
<MsTag
class="ml-2"
:self-style="{
border: `1px solid ${color}`,
color: color,
backgroundColor: 'white',
}"
>
{{ record.testPlanNum }}
</MsTag>
</a-tooltip>
</div>
</template>
<template #triggerMode="{ record }">
<span>{{ t(TriggerModeLabel[record.triggerMode as keyof typeof TriggerModeLabel]) }}</span>
</template>
@ -65,6 +82,7 @@
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import { MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import caseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
import ExecStatus from '@/views/api-test/report/component/execStatus.vue';
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
@ -117,7 +135,7 @@
dataIndex: 'num',
slotName: 'num',
sortIndex: 1,
width: 150,
width: 280,
},
{
title: 'apiTestManagement.executeMethod',
@ -222,6 +240,8 @@
showResponse.value = true;
}
const color = 'rgb(var(--primary-7))';
onBeforeMount(() => {
loadExecuteList();
});
@ -237,6 +257,7 @@
.ms-scroll-bar();
}
.history-table-before {
display: flex;
justify-content: space-between;

View File

@ -2,7 +2,21 @@
<div>
<ms-base-table v-bind="propsRes" no-disable filter-icon-align-left v-on="propsEvent">
<template #num="{ record }">
<span type="text" class="px-0">{{ record.num }}</span>
<div class="flex items-center justify-start">
<span type="text" class="px-0">{{ record.num }}</span>
<a-tooltip v-if="record.testPlanNum" :content="record.testPlanNum">
<MsTag
class="ml-2"
:self-style="{
border: `1px solid ${color}`,
color: color,
backgroundColor: 'white',
}"
>
{{ record.testPlanNum }}
</MsTag>
</a-tooltip>
</div>
</template>
<template #triggerMode="{ record }">
@ -60,6 +74,7 @@
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import { MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import caseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
import ExecStatus from '@/views/api-test/report/component/execStatus.vue';
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
@ -108,7 +123,7 @@
dataIndex: 'id',
slotName: 'num',
fixed: 'left',
width: 150,
width: 180,
},
{
title: 'apiScenario.executeHistory.execution.triggerMode',
@ -206,6 +221,8 @@
const showScenarioReportVisible = ref(false);
const reportId = ref('');
const color = 'rgb(var(--primary-7))';
function showResult(record: ExecuteHistoryItem) {
reportId.value = record.id;
showScenarioReportVisible.value = true;