From f301e4fe0aaa7388a7ee47fead58e6c207159133 Mon Sep 17 00:00:00 2001 From: song-tianyang Date: Mon, 25 Jul 2022 16:55:51 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95):=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95=E9=A6=96?= =?UTF-8?q?=E9=A1=B5=E4=B8=AD=E6=9C=AA=E8=A6=86=E7=9B=96=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E8=B7=B3=E8=BD=AC=E6=9F=A5=E8=AF=A2=E6=95=B0=E6=8D=AE=E4=B8=8D?= =?UTF-8?q?=E5=AF=B9=E7=9A=84=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --bug=1015150 --user=宋天阳 【接口测试】首页-接口、场景用例数量统计,已覆盖/未覆盖数量跳转后没有显示对应的接口 https://www.tapd.cn/55049933/s/1210220 --- .../api/controller/APITestController.java | 2 +- .../dto/definition/ApiDefinitionRequest.java | 5 + .../api/service/ApiAutomationService.java | 16 +-- .../api/service/ApiDefinitionService.java | 20 ++++ .../mapper/ext/ExtApiDefinitionMapper.xml | 102 +++++++++++------- .../definition/components/list/ApiList.vue | 4 + 6 files changed, 99 insertions(+), 50 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/controller/APITestController.java b/backend/src/main/java/io/metersphere/api/controller/APITestController.java index 87f1d0046a..032ce87665 100644 --- a/backend/src/main/java/io/metersphere/api/controller/APITestController.java +++ b/backend/src/main/java/io/metersphere/api/controller/APITestController.java @@ -319,7 +319,7 @@ public class APITestController { */ List apiNoCaseList = apiDefinitionService.selectEffectiveIdByProjectIdAndHaveNotCase(projectId); Map> scenarioUrlList = apiAutomationService.selectScenarioUseUrlByProjectId(projectId); - int apiInScenario = apiAutomationService.countApiInScenario(projectId, scenarioUrlList, apiNoCaseList); + int apiInScenario = apiAutomationService.getApiIdInScenario(projectId, scenarioUrlList, apiNoCaseList).size(); try { if (effectiveApiCount == 0) { diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionRequest.java b/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionRequest.java index 69848fba1b..e42f6fba86 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionRequest.java @@ -4,6 +4,8 @@ import io.metersphere.controller.request.BaseQueryRequest; import lombok.Getter; import lombok.Setter; +import java.util.List; + @Getter @Setter public class ApiDefinitionRequest extends BaseQueryRequest { @@ -29,6 +31,9 @@ public class ApiDefinitionRequest extends BaseQueryRequest { private String path; private String method; + //被场景覆盖的接口id集合 + private List coverageIds; + // 测试计划是否允许重复 private boolean repeatCase; //是否进入待更新列表 diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 9c90c21111..8a00c5dd25 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -1776,7 +1776,7 @@ public class ApiAutomationService { if (CollectionUtils.isEmpty(apiList)) { return coverage; } - int urlContainsCount = this.countApiInScenario(projectId, scenarioUrlMap, apiList); + int urlContainsCount = this.getApiIdInScenario(projectId, scenarioUrlMap, apiList).size(); coverage.setCoverate(urlContainsCount); coverage.setNotCoverate(apiList.size() - urlContainsCount); float coverageRageNumber = (float) urlContainsCount * 100 / apiList.size(); @@ -1785,9 +1785,9 @@ public class ApiAutomationService { return coverage; } - public int countApiInScenario(String projectId, Map> scenarioUrlMap, List apiList) { - int urlContainsCount = 0; - if (MapUtils.isNotEmpty(scenarioUrlMap)) { + public List getApiIdInScenario(String projectId, Map> scenarioUrlMap, List apiList) { + List apiIdList = new ArrayList<>(); + if (MapUtils.isNotEmpty(scenarioUrlMap) && CollectionUtils.isNotEmpty(apiList)) { ProjectApplication urlRepeatableConfig = projectApplicationService.getProjectApplication(projectId, ProjectApplicationType.URL_REPEATABLE.name()); boolean isUrlRepeatable = BooleanUtils.toBoolean(urlRepeatableConfig.getTypeValue()); for (ApiDefinition model : apiList) { @@ -1799,26 +1799,26 @@ public class ApiAutomationService { if (StringUtils.isNotEmpty(url)) { boolean urlMatched = MockApiUtils.isUrlMatch(model.getPath(), url); if (urlMatched) { - urlContainsCount++; + apiIdList.add(model.getId()); } } } else { Collection scenarioUrlList = scenarioUrlMap.get(model.getMethod()).values(); boolean matchedUrl = MockApiUtils.isUrlInList(model.getPath(), scenarioUrlList); if (matchedUrl) { - urlContainsCount++; + apiIdList.add(model.getId()); } } } } else { Map stepIdAndUrlMap = scenarioUrlMap.get("MS_NOT_HTTP"); if (stepIdAndUrlMap != null && stepIdAndUrlMap.containsKey(model.getId())) { - urlContainsCount++; + apiIdList.add(model.getId()); } } } } - return urlContainsCount; + return apiIdList; } public ScenarioEnv getApiScenarioProjectId(String id) { diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index 586668de5d..027a9ba578 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -164,6 +164,9 @@ public class ApiDefinitionService { private ApiScenarioReferenceIdMapper apiScenarioReferenceIdMapper; @Resource private ApiScenarioMapper apiScenarioMapper; + @Lazy + @Resource + private ApiAutomationService apiAutomationService; private final ThreadLocal currentApiOrder = new ThreadLocal<>(); private final ThreadLocal currentApiCaseOrder = new ThreadLocal<>(); @@ -323,6 +326,23 @@ public class ApiDefinitionService { } } } + if (StringUtils.isNotEmpty(request.getProjectId())) { + List definitionList = null; + if (StringUtils.equalsAnyIgnoreCase(request.getApiCoverage(), "uncoverage", "coverage")) { + //计算没有用例接口的覆盖数量 + definitionList = this.selectEffectiveIdByProjectIdAndHaveNotCase(request.getProjectId()); + } + if (StringUtils.equalsAnyIgnoreCase(request.getScenarioCoverage(), "uncoverage", "coverage")) { + //计算全部用例 + definitionList = this.selectEffectiveIdByProjectId(request.getProjectId()); + } + //如果查询条件中有未覆盖/已覆盖, 则需要解析出没有用例的接口中,有多少是符合场景覆盖规律的。然后将这些接口的id作为查询参数 + Map> scenarioUrlList = apiAutomationService.selectScenarioUseUrlByProjectId(request.getProjectId()); + List apiIdInScenario = apiAutomationService.getApiIdInScenario(request.getProjectId(), scenarioUrlList, definitionList); + if (CollectionUtils.isNotEmpty(apiIdInScenario)) { + request.setCoverageIds(apiIdInScenario); + } + } return request; } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml index 5c49edb1cf..57ffebcec2 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml @@ -785,24 +785,30 @@ - + and api_definition.id not in (SELECT api_definition_id FROM api_test_case) - and - api_definition.id not in ( - SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in - (SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') AND reference_id is not null - ) + + and + api_definition.id not in ( + + #{nodeId} + + ) + and ( api_definition.id in (SELECT api_definition_id FROM api_test_case) - or - api_definition.id in ( - SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in - (SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null - ) + + or + api_definition.id in ( + + #{nodeId} + + ) + ) @@ -814,18 +820,22 @@ (SELECT api_definition_id FROM api_test_case) - and api_definition.id not in - ( - SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in - (SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null - ) + + and api_definition.id not in ( + + #{nodeId} + + ) + - and api_definition.id in - ( - SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in - (SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null - ) + + and api_definition.id in ( + + #{nodeId} + + ) + @@ -892,21 +902,27 @@ and api_definition.id not in (SELECT api_definition_id FROM api_test_case) - and - api_definition.id not in ( - SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in - (SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') AND reference_id is not null - ) + + and + api_definition.id not in ( + + #{nodeId} + + ) + and ( api_definition.id in (SELECT api_definition_id FROM api_test_case) - or - api_definition.id in ( - SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in - (SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') - ) + + or + api_definition.id in ( + + #{nodeId} + + ) + ) @@ -918,18 +934,22 @@ (SELECT api_definition_id FROM api_test_case) - and api_definition.id not in - ( - SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in - (SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null - ) + + and api_definition.id not in ( + + #{nodeId} + + ) + - and api_definition.id in - ( - SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in - (SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null - ) + + and api_definition.id in ( + + #{nodeId} + + ) + diff --git a/frontend/src/business/components/api/definition/components/list/ApiList.vue b/frontend/src/business/components/api/definition/components/list/ApiList.vue index 6c9258de80..d45c068bbd 100644 --- a/frontend/src/business/components/api/definition/components/list/ApiList.vue +++ b/frontend/src/business/components/api/definition/components/list/ApiList.vue @@ -635,9 +635,11 @@ export default { break; case 'notCoverate': this.condition.apiCoverage = 'uncoverage'; + this.condition.scenarioCoverage = null; break; case 'coverate': this.condition.apiCoverage = 'coverage'; + this.condition.scenarioCoverage = null; break; case 'unCoverageTestCase': this.condition.apiCaseCoverage = 'uncoverage'; @@ -647,9 +649,11 @@ export default { break; case 'coverageScenario': this.condition.scenarioCoverage = 'coverage'; + this.condition.apiCoverage = null; break; case 'unCoverageScenario': this.condition.scenarioCoverage = 'uncoverage'; + this.condition.apiCoverage = null; break; case 'Prepare': this.condition.filters.status = [this.selectDataRange];