fix(接口测试): 修复接口测试首页中未覆盖接口跳转查询数据不对的缺陷

--bug=1015150 --user=宋天阳 【接口测试】首页-接口、场景用例数量统计,已覆盖/未覆盖数量跳转后没有显示对应的接口
https://www.tapd.cn/55049933/s/1210220
This commit is contained in:
song-tianyang 2022-07-25 16:55:51 +08:00 committed by 建国
parent 74cae34419
commit f301e4fe0a
6 changed files with 99 additions and 50 deletions

View File

@ -319,7 +319,7 @@ public class APITestController {
*/ */
List<ApiDefinition> apiNoCaseList = apiDefinitionService.selectEffectiveIdByProjectIdAndHaveNotCase(projectId); List<ApiDefinition> apiNoCaseList = apiDefinitionService.selectEffectiveIdByProjectIdAndHaveNotCase(projectId);
Map<String, Map<String, String>> scenarioUrlList = apiAutomationService.selectScenarioUseUrlByProjectId(projectId); Map<String, Map<String, String>> scenarioUrlList = apiAutomationService.selectScenarioUseUrlByProjectId(projectId);
int apiInScenario = apiAutomationService.countApiInScenario(projectId, scenarioUrlList, apiNoCaseList); int apiInScenario = apiAutomationService.getApiIdInScenario(projectId, scenarioUrlList, apiNoCaseList).size();
try { try {
if (effectiveApiCount == 0) { if (effectiveApiCount == 0) {

View File

@ -4,6 +4,8 @@ import io.metersphere.controller.request.BaseQueryRequest;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.List;
@Getter @Getter
@Setter @Setter
public class ApiDefinitionRequest extends BaseQueryRequest { public class ApiDefinitionRequest extends BaseQueryRequest {
@ -29,6 +31,9 @@ public class ApiDefinitionRequest extends BaseQueryRequest {
private String path; private String path;
private String method; private String method;
//被场景覆盖的接口id集合
private List<String> coverageIds;
// 测试计划是否允许重复 // 测试计划是否允许重复
private boolean repeatCase; private boolean repeatCase;
//是否进入待更新列表 //是否进入待更新列表

View File

@ -1776,7 +1776,7 @@ public class ApiAutomationService {
if (CollectionUtils.isEmpty(apiList)) { if (CollectionUtils.isEmpty(apiList)) {
return coverage; return coverage;
} }
int urlContainsCount = this.countApiInScenario(projectId, scenarioUrlMap, apiList); int urlContainsCount = this.getApiIdInScenario(projectId, scenarioUrlMap, apiList).size();
coverage.setCoverate(urlContainsCount); coverage.setCoverate(urlContainsCount);
coverage.setNotCoverate(apiList.size() - urlContainsCount); coverage.setNotCoverate(apiList.size() - urlContainsCount);
float coverageRageNumber = (float) urlContainsCount * 100 / apiList.size(); float coverageRageNumber = (float) urlContainsCount * 100 / apiList.size();
@ -1785,9 +1785,9 @@ public class ApiAutomationService {
return coverage; return coverage;
} }
public int countApiInScenario(String projectId, Map<String, Map<String, String>> scenarioUrlMap, List<ApiDefinition> apiList) { public List<String> getApiIdInScenario(String projectId, Map<String, Map<String, String>> scenarioUrlMap, List<ApiDefinition> apiList) {
int urlContainsCount = 0; List<String> apiIdList = new ArrayList<>();
if (MapUtils.isNotEmpty(scenarioUrlMap)) { if (MapUtils.isNotEmpty(scenarioUrlMap) && CollectionUtils.isNotEmpty(apiList)) {
ProjectApplication urlRepeatableConfig = projectApplicationService.getProjectApplication(projectId, ProjectApplicationType.URL_REPEATABLE.name()); ProjectApplication urlRepeatableConfig = projectApplicationService.getProjectApplication(projectId, ProjectApplicationType.URL_REPEATABLE.name());
boolean isUrlRepeatable = BooleanUtils.toBoolean(urlRepeatableConfig.getTypeValue()); boolean isUrlRepeatable = BooleanUtils.toBoolean(urlRepeatableConfig.getTypeValue());
for (ApiDefinition model : apiList) { for (ApiDefinition model : apiList) {
@ -1799,26 +1799,26 @@ public class ApiAutomationService {
if (StringUtils.isNotEmpty(url)) { if (StringUtils.isNotEmpty(url)) {
boolean urlMatched = MockApiUtils.isUrlMatch(model.getPath(), url); boolean urlMatched = MockApiUtils.isUrlMatch(model.getPath(), url);
if (urlMatched) { if (urlMatched) {
urlContainsCount++; apiIdList.add(model.getId());
} }
} }
} else { } else {
Collection<String> scenarioUrlList = scenarioUrlMap.get(model.getMethod()).values(); Collection<String> scenarioUrlList = scenarioUrlMap.get(model.getMethod()).values();
boolean matchedUrl = MockApiUtils.isUrlInList(model.getPath(), scenarioUrlList); boolean matchedUrl = MockApiUtils.isUrlInList(model.getPath(), scenarioUrlList);
if (matchedUrl) { if (matchedUrl) {
urlContainsCount++; apiIdList.add(model.getId());
} }
} }
} }
} else { } else {
Map<String, String> stepIdAndUrlMap = scenarioUrlMap.get("MS_NOT_HTTP"); Map<String, String> stepIdAndUrlMap = scenarioUrlMap.get("MS_NOT_HTTP");
if (stepIdAndUrlMap != null && stepIdAndUrlMap.containsKey(model.getId())) { if (stepIdAndUrlMap != null && stepIdAndUrlMap.containsKey(model.getId())) {
urlContainsCount++; apiIdList.add(model.getId());
} }
} }
} }
} }
return urlContainsCount; return apiIdList;
} }
public ScenarioEnv getApiScenarioProjectId(String id) { public ScenarioEnv getApiScenarioProjectId(String id) {

View File

@ -164,6 +164,9 @@ public class ApiDefinitionService {
private ApiScenarioReferenceIdMapper apiScenarioReferenceIdMapper; private ApiScenarioReferenceIdMapper apiScenarioReferenceIdMapper;
@Resource @Resource
private ApiScenarioMapper apiScenarioMapper; private ApiScenarioMapper apiScenarioMapper;
@Lazy
@Resource
private ApiAutomationService apiAutomationService;
private final ThreadLocal<Long> currentApiOrder = new ThreadLocal<>(); private final ThreadLocal<Long> currentApiOrder = new ThreadLocal<>();
private final ThreadLocal<Long> currentApiCaseOrder = new ThreadLocal<>(); private final ThreadLocal<Long> currentApiCaseOrder = new ThreadLocal<>();
@ -323,6 +326,23 @@ public class ApiDefinitionService {
} }
} }
} }
if (StringUtils.isNotEmpty(request.getProjectId())) {
List<ApiDefinition> 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<String, Map<String, String>> scenarioUrlList = apiAutomationService.selectScenarioUseUrlByProjectId(request.getProjectId());
List<String> apiIdInScenario = apiAutomationService.getApiIdInScenario(request.getProjectId(), scenarioUrlList, definitionList);
if (CollectionUtils.isNotEmpty(apiIdInScenario)) {
request.setCoverageIds(apiIdInScenario);
}
}
return request; return request;
} }

View File

@ -785,24 +785,30 @@
</choose> </choose>
<include refid="filter"/> <include refid="filter"/>
<if test="request.apiCoverage == 'uncoverage' "> <if test="request.apiCoverage == 'uncoverage'">
and and
api_definition.id not in (SELECT api_definition_id FROM api_test_case) api_definition.id not in (SELECT api_definition_id FROM api_test_case)
<if test=" request.coverageIds != null and request.coverageIds.size() > 0">
and and
api_definition.id not in ( api_definition.id not in (
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in <foreach collection="request.coverageIds" item="nodeId" separator="," open="(" close=")">
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') AND reference_id is not null #{nodeId}
</foreach>
) )
</if> </if>
</if>
<if test="request.apiCoverage == 'coverage' "> <if test="request.apiCoverage == 'coverage' ">
and and
( (
api_definition.id in (SELECT api_definition_id FROM api_test_case) api_definition.id in (SELECT api_definition_id FROM api_test_case)
<if test=" request.coverageIds != null and request.coverageIds.size() > 0">
or or
api_definition.id in ( api_definition.id in (
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in <foreach collection="request.coverageIds" item="nodeId" separator="," open="(" close=")">
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null #{nodeId}
</foreach>
) )
</if>
) )
</if> </if>
<if test="request.apiCaseCoverage == 'uncoverage' "> <if test="request.apiCaseCoverage == 'uncoverage' ">
@ -814,19 +820,23 @@
(SELECT api_definition_id FROM api_test_case) (SELECT api_definition_id FROM api_test_case)
</if> </if>
<if test="request.scenarioCoverage == 'uncoverage' "> <if test="request.scenarioCoverage == 'uncoverage' ">
and api_definition.id not in <if test=" request.coverageIds != null and request.coverageIds.size() > 0">
( and api_definition.id not in (
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in <foreach collection="request.coverageIds" item="nodeId" separator="," open="(" close=")">
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null #{nodeId}
</foreach>
) )
</if> </if>
</if>
<if test="request.scenarioCoverage == 'coverage' "> <if test="request.scenarioCoverage == 'coverage' ">
and api_definition.id in <if test=" request.coverageIds != null and request.coverageIds.size() > 0">
( and api_definition.id in (
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in <foreach collection="request.coverageIds" item="nodeId" separator="," open="(" close=")">
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null #{nodeId}
</foreach>
) )
</if> </if>
</if>
<include refid="queryVersionCondition"> <include refid="queryVersionCondition">
<property name="versionTable" value="api_definition"/> <property name="versionTable" value="api_definition"/>
</include> </include>
@ -892,21 +902,27 @@
<if test="request.apiCoverage == 'uncoverage' "> <if test="request.apiCoverage == 'uncoverage' ">
and and
api_definition.id not in (SELECT api_definition_id FROM api_test_case) api_definition.id not in (SELECT api_definition_id FROM api_test_case)
<if test=" request.coverageIds != null and request.coverageIds.size() > 0">
and and
api_definition.id not in ( api_definition.id not in (
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in <foreach collection="request.coverageIds" item="nodeId" separator="," open="(" close=")">
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') AND reference_id is not null #{nodeId}
</foreach>
) )
</if> </if>
</if>
<if test="request.apiCoverage == 'coverage' "> <if test="request.apiCoverage == 'coverage' ">
and and
( (
api_definition.id in (SELECT api_definition_id FROM api_test_case) api_definition.id in (SELECT api_definition_id FROM api_test_case)
<if test=" request.coverageIds != null and request.coverageIds.size() > 0">
or or
api_definition.id in ( api_definition.id in (
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in <foreach collection="request.coverageIds" item="nodeId" separator="," open="(" close=")">
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') #{nodeId}
</foreach>
) )
</if>
) )
</if> </if>
<if test="request.apiCaseCoverage == 'uncoverage' "> <if test="request.apiCaseCoverage == 'uncoverage' ">
@ -918,19 +934,23 @@
(SELECT api_definition_id FROM api_test_case) (SELECT api_definition_id FROM api_test_case)
</if> </if>
<if test="request.scenarioCoverage == 'uncoverage' "> <if test="request.scenarioCoverage == 'uncoverage' ">
and api_definition.id not in <if test=" request.coverageIds != null and request.coverageIds.size() > 0">
( and api_definition.id not in (
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in <foreach collection="request.coverageIds" item="nodeId" separator="," open="(" close=")">
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null #{nodeId}
</foreach>
) )
</if> </if>
</if>
<if test="request.scenarioCoverage == 'coverage' "> <if test="request.scenarioCoverage == 'coverage' ">
and api_definition.id in <if test=" request.coverageIds != null and request.coverageIds.size() > 0">
( and api_definition.id in (
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in <foreach collection="request.coverageIds" item="nodeId" separator="," open="(" close=")">
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null #{nodeId}
</foreach>
) )
</if> </if>
</if>
<include refid="queryVersionCondition"> <include refid="queryVersionCondition">
<property name="versionTable" value="api_definition"/> <property name="versionTable" value="api_definition"/>
</include> </include>

View File

@ -635,9 +635,11 @@ export default {
break; break;
case 'notCoverate': case 'notCoverate':
this.condition.apiCoverage = 'uncoverage'; this.condition.apiCoverage = 'uncoverage';
this.condition.scenarioCoverage = null;
break; break;
case 'coverate': case 'coverate':
this.condition.apiCoverage = 'coverage'; this.condition.apiCoverage = 'coverage';
this.condition.scenarioCoverage = null;
break; break;
case 'unCoverageTestCase': case 'unCoverageTestCase':
this.condition.apiCaseCoverage = 'uncoverage'; this.condition.apiCaseCoverage = 'uncoverage';
@ -647,9 +649,11 @@ export default {
break; break;
case 'coverageScenario': case 'coverageScenario':
this.condition.scenarioCoverage = 'coverage'; this.condition.scenarioCoverage = 'coverage';
this.condition.apiCoverage = null;
break; break;
case 'unCoverageScenario': case 'unCoverageScenario':
this.condition.scenarioCoverage = 'uncoverage'; this.condition.scenarioCoverage = 'uncoverage';
this.condition.apiCoverage = null;
break; break;
case 'Prepare': case 'Prepare':
this.condition.filters.status = [this.selectDataRange]; this.condition.filters.status = [this.selectDataRange];