feat(接口测试): 接口定义页面增加覆盖和不覆盖的筛选

This commit is contained in:
Jianguo-Genius 2024-12-04 14:47:28 +08:00 committed by 建国
parent b96433eb75
commit c71fd05a7c
13 changed files with 286 additions and 18 deletions

View File

@ -0,0 +1,11 @@
package io.metersphere.api.constants;
public class ApiCoverageConstants {
public static final String COVER_FROM = "coverFrom";
public static final String UN_COVER_FROM = "unCoverFrom";
public static final String API_DEFINITION = "apiDefinition";
public static final String API_CASE = "apiCase";
public static final String API_SCENARIO = "apiScenario";
}

View File

@ -98,7 +98,7 @@ public class ApiDefinitionController {
@CheckOwner(resourceId = "#projectId", resourceType = "project") @CheckOwner(resourceId = "#projectId", resourceType = "project")
public ApiCoverageDTO rage(@PathVariable String projectId) { public ApiCoverageDTO rage(@PathVariable String projectId) {
// 筛选出所有 API ID HTTP 类型的 API // 筛选出所有 API ID HTTP 类型的 API
List<ApiDefinition> apiDefinitions = extApiDefinitionMapper.selectBaseInfoByProjectId(projectId); List<ApiDefinition> apiDefinitions = extApiDefinitionMapper.selectBaseInfoByProjectId(projectId, null, null);
List<String> apiAllIds = apiDefinitions.stream().map(ApiDefinition::getId).toList(); List<String> apiAllIds = apiDefinitions.stream().map(ApiDefinition::getId).toList();
List<ApiDefinition> httpApiList = apiDefinitions.stream() List<ApiDefinition> httpApiList = apiDefinitions.stream()
.filter(api -> StringUtils.equalsIgnoreCase(api.getProtocol(), "http")) .filter(api -> StringUtils.equalsIgnoreCase(api.getProtocol(), "http"))
@ -106,12 +106,12 @@ public class ApiDefinitionController {
// 获取 API 定义测试用例 ID 和场景步骤中的 API ID // 获取 API 定义测试用例 ID 和场景步骤中的 API ID
List<String> apiDefinitionIdFromCase = extApiTestCaseMapper.selectApiId(projectId); List<String> apiDefinitionIdFromCase = extApiTestCaseMapper.selectApiId(projectId);
List<String> apiInScenarioStep = new ArrayList<>(extApiScenarioStepMapper.selectResourceId(projectId, ApiScenarioStepType.API.name())); List<String> apiInScenarioStep = new ArrayList<>(extApiScenarioStepMapper.selectResourceId(projectId, ApiScenarioStepType.API.name(), null));
List<String> apiCaseIdInStep = extApiScenarioStepMapper.selectResourceId(projectId, ApiScenarioStepType.API_CASE.name()); List<String> apiCaseIdInStep = extApiScenarioStepMapper.selectResourceId(projectId, ApiScenarioStepType.API_CASE.name(), null);
// 如果有场景步骤中的 API 用例 ID追加相关 API ID // 如果有场景步骤中的 API 用例 ID追加相关 API ID
if (CollectionUtils.isNotEmpty(apiCaseIdInStep)) { if (CollectionUtils.isNotEmpty(apiCaseIdInStep)) {
List<String> apiCaseIdInScenarioStep = extApiTestCaseMapper.selectApiIdByCaseId(apiCaseIdInStep); List<String> apiCaseIdInScenarioStep = extApiTestCaseMapper.selectApiIdByCaseId(apiCaseIdInStep, null, null);
apiInScenarioStep.addAll(apiCaseIdInScenarioStep); apiInScenarioStep.addAll(apiCaseIdInScenarioStep);
} }
@ -198,6 +198,7 @@ public class ApiDefinitionController {
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ) @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public Pager<List<ApiDefinitionDTO>> getPage(@Validated @RequestBody ApiDefinitionPageRequest request) { public Pager<List<ApiDefinitionDTO>> getPage(@Validated @RequestBody ApiDefinitionPageRequest request) {
apiDefinitionService.initApiSelectIds(request);
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString("id")) ? request.getSortString("id") : request.getDeleted() ? "delete_time desc, id desc" : "pos desc, id desc"); StringUtils.isNotBlank(request.getSortString("id")) ? request.getSortString("id") : request.getDeleted() ? "delete_time desc, id desc" : "pos desc, id desc");
return PageUtils.setPageInfo(page, apiDefinitionService.getApiDefinitionPage(request, SessionUtils.getUserId())); return PageUtils.setPageInfo(page, apiDefinitionService.getApiDefinitionPage(request, SessionUtils.getUserId()));

View File

@ -46,4 +46,10 @@ public class ApiDefinitionPageRequest extends BasePageRequest {
@Schema(description = "删除状态(状态为 1 时为回收站数据)") @Schema(description = "删除状态(状态为 1 时为回收站数据)")
private Boolean deleted = false; private Boolean deleted = false;
@Schema(description = "本次查询包含的ID(一般由后台计算后得出)")
private List<String> includeIds = new ArrayList<>();
@Schema(description = "本次查询不包含的ID(一般由后台计算后得出)")
private List<String> excludeIds = new ArrayList<>();
} }

View File

@ -34,4 +34,11 @@ public class ApiModuleRequest extends BaseCondition {
@Schema(description = "测试计划id") @Schema(description = "测试计划id")
private String testPlanId; private String testPlanId;
@Schema(description = "本次查询包含的ID(一般由后台计算后得出)")
private List<String> includeIds = new ArrayList<>();
@Schema(description = "本次查询不包含的ID(一般由后台计算后得出)")
private List<String> excludeIds = new ArrayList<>();
} }

View File

@ -35,7 +35,7 @@ public interface ExtApiDefinitionMapper {
Long getPos(@Param("projectId") String projectId); Long getPos(@Param("projectId") String projectId);
@BaseConditionFilter @BaseConditionFilter
List<String> getIds(@Param("request") TableBatchProcessDTO request, @Param("projectId") String projectId, @Param("protocols") List<String> protocols, @Param("deleted") boolean deleted); List<String> getIds(@Param("request") TableBatchProcessDTO request, @Param("projectId") String projectId, @Param("protocols") List<String> protocols, @Param("deleted") boolean deleted, @Param("includeIds") List<String> includeIds, @Param("excludeIds") List<String> excludeIds);
@BaseConditionFilter @BaseConditionFilter
List<String> getIdsBySort(@Param("request") TableBatchProcessDTO request, @Param("projectId") String projectId, @Param("protocols") List<String> protocols, @Param("orderColumns") String orderColumns, @Param("deleted") boolean deleted); List<String> getIdsBySort(@Param("request") TableBatchProcessDTO request, @Param("projectId") String projectId, @Param("protocols") List<String> protocols, @Param("orderColumns") String orderColumns, @Param("deleted") boolean deleted);
@ -129,5 +129,5 @@ public interface ExtApiDefinitionMapper {
List<ApiDefinition> getCreateApiList(@Param("projectId") String projectId, @Param("startTime") Long startTime, @Param("endTime") Long endTime); List<ApiDefinition> getCreateApiList(@Param("projectId") String projectId, @Param("startTime") Long startTime, @Param("endTime") Long endTime);
List<ApiDefinition> selectBaseInfoByProjectId(String projectId); List<ApiDefinition> selectBaseInfoByProjectId(@Param("projectId") String projectId, @Param("protocols") List<String> protocols, @Param("ignoreApiIds") List<String> ignoreApiIds);
} }

View File

@ -86,6 +86,18 @@
#{item} #{item}
</foreach> </foreach>
</if> </if>
<if test="includeIds != null and includeIds.size() > 0">
and api_definition.id in
<foreach collection="includeIds" item="includeId" separator="," open="(" close=")">
#{includeId}
</foreach>
</if>
<if test="excludeIds != null and excludeIds.size() > 0">
and api_definition.id not in
<foreach collection="excludeIds" item="excludeId" separator="," open="(" close=")">
#{excludeId}
</foreach>
</if>
<include refid="queryWhereConditionByBaseQueryRequest"/> <include refid="queryWhereConditionByBaseQueryRequest"/>
</select> </select>
@ -264,6 +276,18 @@
<if test="request.projectId != null and request.projectId != ''"> <if test="request.projectId != null and request.projectId != ''">
and api_definition.project_id = #{request.projectId} and api_definition.project_id = #{request.projectId}
</if> </if>
<if test="request.includeIds != null and request.includeIds.size() > 0">
and api_definition.id in
<foreach collection="request.includeIds" item="includeId" separator="," open="(" close=")">
#{includeId}
</foreach>
</if>
<if test="request.excludeIds != null and request.excludeIds.size() > 0">
and api_definition.id not in
<foreach collection="request.excludeIds" item="excludeId" separator="," open="(" close=")">
#{excludeId}
</foreach>
</if>
<if test="request.protocols != null and request.protocols.size() > 0"> <if test="request.protocols != null and request.protocols.size() > 0">
and api_definition.protocol in and api_definition.protocol in
<foreach collection="request.protocols" item="protocol" separator="," open="(" close=")"> <foreach collection="request.protocols" item="protocol" separator="," open="(" close=")">
@ -843,7 +867,19 @@
<select id="selectBaseInfoByProjectId" resultType="io.metersphere.api.domain.ApiDefinition"> <select id="selectBaseInfoByProjectId" resultType="io.metersphere.api.domain.ApiDefinition">
SELECT id, path, method, protocol SELECT id, path, method, protocol
FROM api_definition FROM api_definition
WHERE project_id = #{0} WHERE project_id = #{projectId}
AND deleted IS FALSE AND deleted IS FALSE
<if test="protocols != null and protocols.size() > 0">
AND protocol IN
<foreach collection="protocols" item="protocol" separator="," open="(" close=")">
#{protocol}
</foreach>
</if>
<if test="ignoreApiIds!= null and ignoreApiIds.size > 0">
AND id NOT IN
<foreach collection="ignoreApiIds" item="ignoreApiId" open="(" separator="," close=")">
#{ignoreApiId}
</foreach>
</if>
</select> </select>
</mapper> </mapper>

View File

@ -26,7 +26,7 @@ public interface ExtApiScenarioStepMapper {
*/ */
List<String> getHasBlobRequestStepIds(@Param("scenarioId") String scenarioId); List<String> getHasBlobRequestStepIds(@Param("scenarioId") String scenarioId);
List<String> selectResourceId(@Param("projectId") String projectId, @Param("stepType") String stepType); List<String> selectResourceId(@Param("projectId") String projectId, @Param("stepType") String stepType, @Param("protocols") List<String> apiProtocols);
List<String> selectCustomRequestConfigByProjectId(String projectId); List<String> selectCustomRequestConfigByProjectId(String projectId);
} }

View File

@ -36,6 +36,16 @@
where step.step_type = #{stepType} where step.step_type = #{stepType}
AND scenario.project_id = #{projectId} AND scenario.project_id = #{projectId}
AND scenario.deleted IS FALSE AND scenario.deleted IS FALSE
<if test="protocols!= null and protocols.size > 0">
AND step.resource_id IN (
select distinct apiCase.id FROM api_definition api
INNER JOIN api_test_case apiCase ON api.id = apiCase.api_definition_id
WHERE api.project_id = #{projectId} AND api.deleted IS FALSE and api.deleted IS FALSE AND api.protocol IN
<foreach collection="protocols" item="protocol" open="(" separator="," close=")">
#{protocol}
</foreach>
)
</if>
</select> </select>
<select id="selectCustomRequestConfigByProjectId" resultType="java.lang.String"> <select id="selectCustomRequestConfigByProjectId" resultType="java.lang.String">
select step.id select step.id

View File

@ -143,5 +143,7 @@ public interface ExtApiTestCaseMapper {
List<String> selectApiId(String projectId); List<String> selectApiId(String projectId);
List<String> selectApiIdByCaseId(@Param("ids") List<String> apiCaseIdInStep); List<String> selectApiIdByProjectAndProtocol(@Param("projectId") String projectId, @Param("protocols") List<String> protocols);
List<String> selectApiIdByCaseId(@Param("ids") List<String> apiCaseIdInStep, @Param("protocols") List<String> apiProtocols, @Param("ignoreApiIds") List<String> ignoreApiIds);
} }

View File

@ -1040,9 +1040,36 @@
AND api.project_id = #{0} AND api.project_id = #{0}
</select> </select>
<select id="selectApiIdByCaseId" resultType="java.lang.String"> <select id="selectApiIdByCaseId" resultType="java.lang.String">
SELECT api_definition_id FROM api_test_case WHERE deleted is false AND id in SELECT DISTINCT apiCase.api_definition_id FROM api_test_case apiCase
INNER JOIN api_definition api ON apiCase.api_definition_id = api.id
WHERE apiCase.deleted IS FALSE AND api.deleted IS FALSE AND apiCase.id in
<foreach collection="ids" item="id" separator="," open="(" close=")"> <foreach collection="ids" item="id" separator="," open="(" close=")">
#{id} #{id}
</foreach> </foreach>
<if test="protocols!= null and protocols.size > 0">
AND api.protocol IN
<foreach collection="protocols" item="protocol" open="(" separator="," close=")">
#{protocol}
</foreach>
</if>
<if test="ignoreApiIds!= null and ignoreApiIds.size > 0">
AND api.id NOT IN
<foreach collection="ignoreApiIds" item="ignoreApiId" open="(" separator="," close=")">
#{ignoreApiId}
</foreach>
</if>
</select>
<select id="selectApiIdByProjectAndProtocol" resultType="java.lang.String">
SELECT distinct api.id
FROM api_test_case apiCase
INNER JOIN api_definition api ON apiCase.api_definition_id = api.id
WHERE apiCase.deleted is FALSE
AND api.deleted is FALSE
AND api.project_id = #{projectId}
AND api.protocol IN
<foreach collection="protocols" item="protocol" separator="," open="(" close=")">
#{protocol}
</foreach>
</select> </select>
</mapper> </mapper>

View File

@ -18,6 +18,7 @@ import io.metersphere.project.dto.NodeSortDTO;
import io.metersphere.project.service.ModuleTreeService; import io.metersphere.project.service.ModuleTreeService;
import io.metersphere.sdk.constants.ModuleConstants; import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.sdk.BaseTreeNode; import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.request.NodeMoveRequest; import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
@ -73,6 +74,9 @@ public class ApiDefinitionModuleService extends ModuleTreeService {
if (!containRequest || CollectionUtils.isEmpty(request.getProtocols())) { if (!containRequest || CollectionUtils.isEmpty(request.getProtocols())) {
return baseTreeNodes; return baseTreeNodes;
} }
ApiDefinitionService apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class);
request.setExcludeIds(apiDefinitionService.getQueryExcludeIds(request.getFilter(), request.getProjectId(), request.getProtocols()));
request.setIncludeIds(apiDefinitionService.getQueryIncludeIds(request.getFilter(), request.getProjectId(), request.getProtocols()));
List<ApiTreeNode> apiTreeNodeList = extApiDefinitionModuleMapper.selectApiDataByRequest(request, deleted); List<ApiTreeNode> apiTreeNodeList = extApiDefinitionModuleMapper.selectApiDataByRequest(request, deleted);
return apiDebugModuleService.getBaseTreeNodes(apiTreeNodeList, baseTreeNodes); return apiDebugModuleService.getBaseTreeNodes(apiTreeNodeList, baseTreeNodes);

View File

@ -1,8 +1,6 @@
package io.metersphere.api.service.definition; package io.metersphere.api.service.definition;
import io.metersphere.api.constants.ApiConstants; import io.metersphere.api.constants.*;
import io.metersphere.api.constants.ApiDefinitionDocType;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.controller.result.ApiResultCode; import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.*; import io.metersphere.api.domain.*;
import io.metersphere.api.dto.*; import io.metersphere.api.dto.*;
@ -16,6 +14,7 @@ import io.metersphere.api.mapper.*;
import io.metersphere.api.service.ApiCommonService; import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteService; import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.ApiFileResourceService; import io.metersphere.api.service.ApiFileResourceService;
import io.metersphere.api.service.scenario.ApiScenarioService;
import io.metersphere.api.utils.ApiDataUtils; import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.api.utils.JsonSchemaBuilder; import io.metersphere.api.utils.JsonSchemaBuilder;
import io.metersphere.plugin.api.spi.AbstractMsTestElement; import io.metersphere.plugin.api.spi.AbstractMsTestElement;
@ -53,6 +52,7 @@ import io.metersphere.system.uid.NumGenerator;
import io.metersphere.system.utils.ServiceUtils; import io.metersphere.system.utils.ServiceUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.ExecutorType;
@ -83,6 +83,9 @@ public class ApiDefinitionService extends MoveNodeService {
@Resource @Resource
private ExtApiDefinitionMapper extApiDefinitionMapper; private ExtApiDefinitionMapper extApiDefinitionMapper;
@Resource
private ExtApiScenarioStepMapper extApiScenarioStepMapper;
@Resource @Resource
private ExtApiDefinitionModuleMapper extApiDefinitionModuleMapper; private ExtApiDefinitionModuleMapper extApiDefinitionModuleMapper;
@ -133,8 +136,10 @@ public class ApiDefinitionService extends MoveNodeService {
@Resource @Resource
private OperationLogBlobMapper operationLogBlobMapper; private OperationLogBlobMapper operationLogBlobMapper;
@Resource @Resource
private ApiExecuteService apiExecuteService; private ApiExecuteService apiExecuteService;
@Resource @Resource
private ApiDefinitionNoticeService apiDefinitionNoticeService; private ApiDefinitionNoticeService apiDefinitionNoticeService;
@ -147,6 +152,77 @@ public class ApiDefinitionService extends MoveNodeService {
return list; return list;
} }
public void initApiSelectIds(ApiDefinitionPageRequest request) {
request.setExcludeIds(this.getQueryExcludeIds(request.getFilter(), request.getProjectId(), request.getProtocols()));
request.setIncludeIds(this.getQueryIncludeIds(request.getFilter(), request.getProjectId(), request.getProtocols()));
}
public List<String> getQueryIncludeIds(Map<String, List<String>> queryFilter, String projectId, List<String> protocol) {
if (queryFilter != null && CollectionUtils.isNotEmpty(queryFilter.get("coverFrom"))) {
String coverFrom = queryFilter.get("coverFrom").getFirst();
if (ApiCoverageConstants.API_DEFINITION.equals(coverFrom)) {
return this.selectApiIdInCaseAndScenarioStep(projectId, protocol);
} else if (ApiCoverageConstants.API_CASE.equals(coverFrom)) {
return this.selectApiIdInCase(projectId, protocol);
} else if (ApiCoverageConstants.API_SCENARIO.equals(coverFrom)) {
return this.selectApiIdInScenarioStep(projectId, protocol, null);
}
}
return null;
}
public List<String> getQueryExcludeIds(Map<String, List<String>> queryFilter, String projectId, List<String> protocol) {
if (queryFilter != null && CollectionUtils.isNotEmpty(queryFilter.get("unCoverFrom"))) {
String unCoverFrom = queryFilter.get("unCoverFrom").getFirst();
if (ApiCoverageConstants.API_DEFINITION.equals(unCoverFrom)) {
return this.selectApiIdInCaseAndScenarioStep(projectId, protocol);
} else if (ApiCoverageConstants.API_CASE.equals(unCoverFrom)) {
return this.selectApiIdInCase(projectId, protocol);
} else if (ApiCoverageConstants.API_SCENARIO.equals(unCoverFrom)) {
return this.selectApiIdInScenarioStep(projectId, protocol, null);
}
}
return null;
}
private List<String> selectApiIdInCaseAndScenarioStep(String projectId, List<String> protocols) {
List<String> apiInCase = this.selectApiIdInCase(projectId, protocols);
List<String> apiInScenarioStep = this.selectApiIdInScenarioStep(projectId, protocols, apiInCase);
return ListUtils.union(apiInCase, apiInScenarioStep);
}
private List<String> selectApiIdInCase(String projectId, List<String> protocols) {
if (CollectionUtils.isEmpty(protocols)) {
return new ArrayList<>();
}
return extApiTestCaseMapper.selectApiIdByProjectAndProtocol(projectId, protocols);
}
private List<String> selectApiIdInScenarioStep(String projectId, List<String> protocols, List<String> ignoreApiIds) {
List<String> apiInScenarioStep = new ArrayList<>(extApiScenarioStepMapper.selectResourceId(projectId, ApiScenarioStepType.API.name(), protocols));
List<String> apiCaseIdInStep = extApiScenarioStepMapper.selectResourceId(projectId, ApiScenarioStepType.API_CASE.name(), protocols);
// 如果有场景步骤中的 API 用例 ID追加相关 API ID
if (CollectionUtils.isNotEmpty(apiCaseIdInStep)) {
List<String> apiCaseIdInScenarioStep = extApiTestCaseMapper.selectApiIdByCaseId(apiCaseIdInStep, protocols, ignoreApiIds);
apiInScenarioStep.addAll(apiCaseIdInScenarioStep);
apiCaseIdInScenarioStep = null;
apiCaseIdInStep = null;
}
if (protocols.contains("HTTP")) {
List<ApiDefinition> apiDefinitions = extApiDefinitionMapper.selectBaseInfoByProjectId(projectId, List.of("HTTP"), ignoreApiIds);
List<ApiDefinition> httpApiList = apiDefinitions.stream()
.filter(api -> StringUtils.equalsIgnoreCase(api.getProtocol(), "http"))
.toList();
apiDefinitions = null;
List<String> apiInStepList = new ArrayList<>(CommonBeanFactory.getBean(ApiScenarioService.class).selectApiIdInCustomRequest(projectId, httpApiList));
apiInScenarioStep.addAll(apiInStepList);
}
return apiInScenarioStep;
}
public List<ApiDefinitionDTO> getDocPage(ApiDefinitionPageRequest request, String userId) { public List<ApiDefinitionDTO> getDocPage(ApiDefinitionPageRequest request, String userId) {
if (CollectionUtils.isEmpty(request.getProtocols())) { if (CollectionUtils.isEmpty(request.getProtocols())) {
return new ArrayList<>(); return new ArrayList<>();
@ -907,7 +983,9 @@ public class ApiDefinitionService extends MoveNodeService {
public <T> List<String> getBatchApiIds(T dto, String projectId, List<String> protocols, boolean deleted, String userId) { public <T> List<String> getBatchApiIds(T dto, String projectId, List<String> protocols, boolean deleted, String userId) {
TableBatchProcessDTO request = (TableBatchProcessDTO) dto; TableBatchProcessDTO request = (TableBatchProcessDTO) dto;
if (request.isSelectAll() && CollectionUtils.isNotEmpty(protocols)) { if (request.isSelectAll() && CollectionUtils.isNotEmpty(protocols)) {
List<String> ids = extApiDefinitionMapper.getIds(request, projectId, protocols, deleted); List<String> includeIds = this.getQueryIncludeIds(request.getCondition().getFilter(), projectId, protocols);
List<String> excludeIds = this.getQueryExcludeIds(request.getCondition().getFilter(), projectId, protocols);
List<String> ids = extApiDefinitionMapper.getIds(request, projectId, protocols, deleted, includeIds, excludeIds);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) { if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
ids.removeAll(request.getExcludeIds()); ids.removeAll(request.getExcludeIds());
} }

View File

@ -5,10 +5,7 @@ import io.metersphere.api.domain.ApiDefinition;
import io.metersphere.api.domain.ApiDefinitionExample; import io.metersphere.api.domain.ApiDefinitionExample;
import io.metersphere.api.domain.ApiScenario; import io.metersphere.api.domain.ApiScenario;
import io.metersphere.api.domain.ApiTestCase; import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.api.dto.definition.ApiCoverageDTO; import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.ApiDefinitionAddRequest;
import io.metersphere.api.dto.definition.ApiTestCaseAddRequest;
import io.metersphere.api.dto.definition.HttpResponse;
import io.metersphere.api.dto.request.http.MsHTTPElement; import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.api.dto.scenario.ApiScenarioAddRequest; import io.metersphere.api.dto.scenario.ApiScenarioAddRequest;
import io.metersphere.api.dto.scenario.ApiScenarioStepRequest; import io.metersphere.api.dto.scenario.ApiScenarioStepRequest;
@ -22,16 +19,19 @@ import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.util.CalculateUtils; 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.dto.AddProjectRequest; import io.metersphere.system.dto.AddProjectRequest;
import io.metersphere.system.log.constants.OperationLogModule; import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.service.CommonProjectService; import io.metersphere.system.service.CommonProjectService;
import io.metersphere.system.uid.IDGenerator; import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ -222,6 +222,31 @@ public class ApiCalculateTest extends BaseTest {
} }
} }
/*
本次接口定义相关数据
"GET""/api/get-test/1",
"/api/get-test/2",
"/api/{/get-test}/3/withCase",
"/api/get-test/4/withCase",// 场景关联它的用例
"/api/get-test/5/never-compare",
"/{api}/{/get-test}/{6}",//这个在接口程度覆盖率和场景程度覆盖率计算中一定会被匹配到
"/api/get-test/{7}",// 这个在接口程度覆盖率和场景程度覆盖率计算中一定会被匹配到
"/api/get-test/8",// 场景关联它的自定义请求
"/api/get-test/9",// 场景关联这个接口
"/api/get-test/10"
"POST""/post/api/test/1",
"/post/api/test/2",
"/post/api/{test}/3/withCase",
"/post/api/test/4/withCase",// 场景关联它的用例
"/post/api/test/5/never-compare",
"/{post}/{api}/{/get-test}/{6}", //这个在接口程度覆盖率和场景程度覆盖率计算中一定会被匹配到
"/post/api/test/{7}", // 这个在接口程度覆盖率和场景程度覆盖率计算中一定会被匹配到
"/post/api/test/8", // 场景关联它的自定义请求
"/post/api/test/9", // 场景关联这个接口
"/post/api/test/10"
*/
@Test @Test
public void calculateTest() throws Exception { public void calculateTest() throws Exception {
ApiDefinitionExample apiDefinitionExample = new ApiDefinitionExample(); ApiDefinitionExample apiDefinitionExample = new ApiDefinitionExample();
@ -244,6 +269,67 @@ public class ApiCalculateTest extends BaseTest {
Assertions.assertEquals(apiCoverageDTO.getApiCoverage(), CalculateUtils.reportPercentage(apiCoverageDTO.getCoverWithApiDefinition(), apiCoverageDTO.getAllApiCount())); Assertions.assertEquals(apiCoverageDTO.getApiCoverage(), CalculateUtils.reportPercentage(apiCoverageDTO.getCoverWithApiDefinition(), apiCoverageDTO.getAllApiCount()));
Assertions.assertEquals("0.00%", CalculateUtils.reportPercentage(0, 0)); Assertions.assertEquals("0.00%", CalculateUtils.reportPercentage(0, 0));
// 表格筛选测试
ApiDefinitionPageRequest request = new ApiDefinitionPageRequest();
request.setProjectId(project.getId());
request.setCurrent(1);
request.setPageSize(10);
request.setDeleted(false);
request.setSort(Map.of("createTime", "asc"));
request.setProtocols(List.of("HTTP"));
Map<String, List<String>> filters = new HashMap<>();
request.setSort(Map.of());
filters.put("coverFrom", List.of(ApiCoverageConstants.API_DEFINITION));
request.setFilter(filters);
MvcResult pageResult = this.requestPostWithOkAndReturn("/api/definition/page", request);
Pager<Object> result = JSON.parseObject(JSON.toJSONString(JSON.parseObject(
pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()), Pager.class);
Assertions.assertEquals(result.getTotal(), 10);
filters = new HashMap<>();
filters.put("unCoverFrom", List.of(ApiCoverageConstants.API_DEFINITION));
request.setFilter(filters);
pageResult = this.requestPostWithOkAndReturn("/api/definition/page", request);
result = JSON.parseObject(JSON.toJSONString(JSON.parseObject(
pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()), Pager.class);
Assertions.assertEquals(result.getTotal(), 10);
filters = new HashMap<>();
filters.put("coverFrom", List.of(ApiCoverageConstants.API_CASE));
request.setFilter(filters);
pageResult = this.requestPostWithOkAndReturn("/api/definition/page", request);
result = JSON.parseObject(JSON.toJSONString(JSON.parseObject(
pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()), Pager.class);
Assertions.assertEquals(result.getTotal(), 4);
filters = new HashMap<>();
filters.put("unCoverFrom", List.of(ApiCoverageConstants.API_CASE));
request.setFilter(filters);
pageResult = this.requestPostWithOkAndReturn("/api/definition/page", request);
result = JSON.parseObject(JSON.toJSONString(JSON.parseObject(
pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()), Pager.class);
Assertions.assertEquals(result.getTotal(), 16);
filters = new HashMap<>();
filters.put("coverFrom", List.of(ApiCoverageConstants.API_SCENARIO));
request.setFilter(filters);
pageResult = this.requestPostWithOkAndReturn("/api/definition/page", request);
result = JSON.parseObject(JSON.toJSONString(JSON.parseObject(
pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()), Pager.class);
Assertions.assertEquals(result.getTotal(), 8);
filters = new HashMap<>();
filters.put("unCoverFrom", List.of(ApiCoverageConstants.API_SCENARIO));
request.setFilter(filters);
pageResult = this.requestPostWithOkAndReturn("/api/definition/page", request);
result = JSON.parseObject(JSON.toJSONString(JSON.parseObject(
pageResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()), Pager.class);
Assertions.assertEquals(result.getTotal(), 12);
} }
@Test @Test