feat(功能用例): 新增获取未关联的接口场景列表,接口场景树,接口场景树统计

This commit is contained in:
guoyuqi 2024-01-18 09:25:35 +08:00 committed by Craftsman
parent b29fa733e8
commit 4fe77a27cf
11 changed files with 558 additions and 18 deletions

View File

@ -13,13 +13,13 @@ import java.util.Map;
*/ */
public interface BaseAssociateApiProvider { public interface BaseAssociateApiProvider {
/** /**
* 获取尚未关联的接口列表 * 获取尚未关联的用例列表
* *
* @param sourceType 关联关系表表名 * @param sourceType 关联关系表表名
* @param sourceName 关联关系表主动关联方字段名称 * @param sourceName 关联关系表主动关联方字段名称
* @param apiCaseColumnName 接口用例id 在关联关系表的字段名称 * @param apiCaseColumnName 接口用例id 在关联关系表的字段名称
* @param testCasePageProviderRequest 接口用例高级搜索条件 * @param testCasePageProviderRequest 接口用例高级搜索条件
* @return List<ApiTestCaseProviderDTO> * @return List<TestCaseProviderDTO> 通用用例集合
*/ */
List<TestCaseProviderDTO> getApiTestCaseList(String sourceType, String sourceName, String apiCaseColumnName, TestCasePageProviderRequest testCasePageProviderRequest); List<TestCaseProviderDTO> getApiTestCaseList(String sourceType, String sourceName, String apiCaseColumnName, TestCasePageProviderRequest testCasePageProviderRequest);

View File

@ -0,0 +1,45 @@
package io.metersphere.provider;
import io.metersphere.api.domain.ApiScenario;
import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import java.util.List;
import java.util.Map;
/**
* @author guoyuqi
*/
public interface BaseAssociateScenarioProvider {
/**
* 获取尚未关联的场景用例列表
*
* @param sourceType 关联关系表表名
* @param sourceName 关联关系表主动关联方字段名称
* @param caseColumnName 场景用例id 在关联关系表的字段名称
* @param testCasePageProviderRequest 用例高级搜索条件
* @return List<TestCaseProviderDTO> 通用用例集合
*/
List<TestCaseProviderDTO> getScenarioCaseList(String sourceType, String sourceName, String caseColumnName, TestCasePageProviderRequest testCasePageProviderRequest);
/**
* 根据用例的搜索条件获取符合条件的接口定义的模块统计数量
*
* @param request 接口用例高级搜索条件
* @param deleted 接口定义是否删除
* @return 接口模块统计数量
*/
Map<String, Long> moduleCount(String sourceType, String sourceName, String apiCaseColumnName, TestCasePageProviderRequest request, boolean deleted);
/**
* 根据页面筛选条件获取批量操作的场景
*
* @return 接口用例的ids
*/
List<ApiScenario> getSelectScenarioCases(AssociateOtherCaseRequest request, Boolean deleted);
}

View File

@ -53,7 +53,7 @@ public class TestCasePageProviderRequest implements Serializable {
@Size(min = 1, max = 50, message = "{api_definition.project_id.length_range}") @Size(min = 1, max = 50, message = "{api_definition.project_id.length_range}")
private String sourceId; private String sourceId;
@Schema(description = "接口pk") @Schema(description = "接口pk(只在关联接口的时候用)")
private String apiDefinitionId; private String apiDefinitionId;
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@ -4,6 +4,11 @@ import io.metersphere.api.domain.ApiScenario;
import io.metersphere.api.dto.scenario.ApiScenarioBatchEditRequest; import io.metersphere.api.dto.scenario.ApiScenarioBatchEditRequest;
import io.metersphere.api.dto.scenario.ApiScenarioDTO; import io.metersphere.api.dto.scenario.ApiScenarioDTO;
import io.metersphere.api.dto.scenario.ApiScenarioPageRequest; import io.metersphere.api.dto.scenario.ApiScenarioPageRequest;
import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@ -17,4 +22,12 @@ public interface ExtApiScenarioMapper {
List<ApiScenario> getTagsByIds(@Param("ids") List<String> ids, @Param("deleted") boolean deleted); List<ApiScenario> getTagsByIds(@Param("ids") List<String> ids, @Param("deleted") boolean deleted);
List<TestCaseProviderDTO> listByProviderRequest(@Param("table") String resourceType, @Param("sourceName") String sourceName, @Param("apiCaseColumnName") String apiCaseColumnName, @Param("request") TestCasePageProviderRequest request, @Param("deleted") boolean deleted);
List<ModuleCountDTO> countModuleIdByProviderRequest(@Param("table") String resourceType, @Param("sourceName") String sourceName, @Param("apiCaseColumnName") String apiCaseColumnName, @Param("request") TestCasePageProviderRequest request, @Param("deleted") boolean deleted);
List<BaseTreeNode> selectIdAndParentIdByProjectId(@Param("projectId") String projectId);
List<ApiScenario> getTestCaseByProvider(@Param("request") AssociateOtherCaseRequest request, @Param("deleted") boolean deleted);
} }

View File

@ -9,6 +9,11 @@
<resultMap id="BaseResultMap" type="io.metersphere.api.domain.ApiScenario"> <resultMap id="BaseResultMap" type="io.metersphere.api.domain.ApiScenario">
<result column="tags" jdbcType="VARCHAR" property="tags" typeHandler="io.metersphere.handler.ListTypeHandler" /> <result column="tags" jdbcType="VARCHAR" property="tags" typeHandler="io.metersphere.handler.ListTypeHandler" />
</resultMap> </resultMap>
<resultMap id="TestCaseProviderDTO" type="io.metersphere.dto.TestCaseProviderDTO">
<result column="tags" jdbcType="VARCHAR" property="tags" typeHandler="io.metersphere.handler.ListTypeHandler" />
</resultMap>
<select id="list" resultMap="ApiScenarioDTO"> <select id="list" resultMap="ApiScenarioDTO">
select select
api_scenario.id, api_scenario.`name`,api_scenario.priority, api_scenario.id, api_scenario.`name`,api_scenario.priority,
@ -52,6 +57,53 @@
</foreach> </foreach>
</select> </select>
<select id="listByProviderRequest" resultMap="TestCaseProviderDTO">
SELECT
api_scenario.id,
api_scenario.project_id,
api_scenario.name,
api_scenario.priority,
api_scenario.tags,
api_scenario.name as versionName
FROM
api_scenario
LEFT JOIN project_version ON api_scenario.version_id = project_version.id
WHERE api_scenario.deleted =#{deleted}
and api_scenario.id not in
(
select associate.${apiCaseColumnName} from ${table} associate where associate.${sourceName} = #{request.sourceId}
)
<include refid="queryWhereConditionByProvider"/>
</select>
<select id="countModuleIdByProviderRequest" resultType="io.metersphere.project.dto.ModuleCountDTO">
SELECT api_scenario.module_id AS moduleId, count(api_scenario.id) AS dataCount
FROM api_scenario
WHERE api_scenario.deleted =#{deleted}
and api_scenario.id not in
(
select associate.${apiCaseColumnName} from ${table} associate where associate.${sourceName} = #{request.sourceId}
)
<include refid="queryWhereConditionByProvider"/>
GROUP BY api_scenario.module_id
</select>
<select id="selectIdAndParentIdByProjectId" resultType="io.metersphere.system.dto.sdk.BaseTreeNode">
SELECT a.id,
a.parent_id AS parentId
FROM api_scenario_module a
WHERE a.project_id = #{projectId}
ORDER BY pos
</select>
<select id="getTestCaseByProvider" resultType="io.metersphere.api.domain.ApiScenario">
SELECT
t1.id, t1.version_id
FROM
api_scenario t1
WHERE t1.deleted =#{deleted}
<include refid="queryWhereConditionByBaseQueryRequest"/>
</select>
<sql id="queryWhereConditionByBaseQueryRequest"> <sql id="queryWhereConditionByBaseQueryRequest">
<if test="request.condition.combine != null"> <if test="request.condition.combine != null">
@ -109,6 +161,40 @@
</sql> </sql>
<sql id="queryWhereConditionByProvider">
<if test="request.keyword != null and request.keyword != ''">
and (
api_scenario.num like concat('%', #{request.keyword},'%')
or api_scenario.name like concat('%', #{request.keyword},'%')
or api_scenario.tags like JSON_CONTAINS(tags, concat('["',#{request.keyword},'"]'))
)
</if>
<if test="request.projectId != null and request.projectId != ''">
and api_scenario.project_id = #{request.projectId}
</if>
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
and api_scenario.module_id in
<foreach collection="request.moduleIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<include refid="filters">
<property name="filter" value="request.filter"/>
</include>
<if test="request.combine != null and request.combine != ''">
<include refid="combine">
<property name="condition" value="request.combine"/>
<property name="name" value="request.name"/>
<property name="ObjectTags" value="request.combine.tags"/>
</include>
</if>
<include refid="queryVersionConditionProvider">
<property name="versionTable" value="api_scenario"/>
</include>
</sql>
<sql id="filters"> <sql id="filters">
<if test="${filter} != null and ${filter}.size() > 0"> <if test="${filter} != null and ${filter}.size() > 0">
<foreach collection="${filter}.entrySet()" index="key" item="values"> <foreach collection="${filter}.entrySet()" index="key" item="values">
@ -253,6 +339,20 @@
AND ${versionTable}.latest = 1 AND ${versionTable}.latest = 1
</if> </if>
</sql> </sql>
<sql id="queryVersionConditionProvider">
<if test="request.versionId != null and request.versionId != ''">
and ${versionTable}.version_id = #{request.versionId}
</if>
<if test="request.refId != null and request.refId != ''">
and ${versionTable}.ref_id = #{request.refId}
</if>
<if test="request.versionId == null and request.refId == null">
AND ${versionTable}.latest = 1
</if>
</sql>
<sql id="queryDocVersionCondition"> <sql id="queryDocVersionCondition">
<if test="request.versionId != null and request.versionId != ''"> <if test="request.versionId != null and request.versionId != ''">
and ${versionTable}.version_id = #{request.versionId} and ${versionTable}.version_id = #{request.versionId}

View File

@ -0,0 +1,90 @@
package io.metersphere.api.provider;
import io.metersphere.api.domain.ApiScenario;
import io.metersphere.api.domain.ApiScenarioExample;
import io.metersphere.api.mapper.ApiScenarioMapper;
import io.metersphere.api.mapper.ExtApiScenarioMapper;
import io.metersphere.api.service.scenario.ApiScenarioModuleService;
import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.provider.BaseAssociateScenarioProvider;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class AssociateScenarioProvider implements BaseAssociateScenarioProvider {
@Resource
private ExtApiScenarioMapper extApiScenarioMapper;
@Resource
private ApiScenarioModuleService apiScenarioModuleService;
@Resource
private ApiScenarioMapper apiScenarioMapper;
private static final String DEBUG_MODULE_COUNT_ALL = "all";
private static final String UNPLANNED_SCENARIO = "api_unplanned_scenario";
@Override
public List<TestCaseProviderDTO> getScenarioCaseList(String sourceType, String sourceName, String caseColumnName, TestCasePageProviderRequest testCasePageProviderRequest) {
return extApiScenarioMapper.listByProviderRequest(sourceType, sourceName, caseColumnName, testCasePageProviderRequest, false);
}
@Override
public Map<String, Long> moduleCount(String sourceType, String sourceName, String apiCaseColumnName, TestCasePageProviderRequest request, boolean deleted) {
request.setModuleIds(null);
//查找根据moduleIds查找模块下的接口数量 查非delete状态的
List<ModuleCountDTO> moduleCountDTOList = extApiScenarioMapper.countModuleIdByProviderRequest(sourceType, sourceName, apiCaseColumnName, request, deleted);
long allCount = getAllCount(moduleCountDTOList);
Map<String, Long> moduleCountMap = getModuleCountMap(request, moduleCountDTOList);
moduleCountMap.put(DEBUG_MODULE_COUNT_ALL, allCount);
return moduleCountMap;
}
@Override
public List<ApiScenario> getSelectScenarioCases(AssociateOtherCaseRequest request, Boolean deleted) {
if (request.isSelectAll()) {
List<ApiScenario> cases = extApiScenarioMapper.getTestCaseByProvider(request, deleted);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
cases = cases.stream().filter(t -> !request.getExcludeIds().contains(t.getId())).toList();
}
return cases;
} else {
ApiScenarioExample apiScenarioExample = new ApiScenarioExample();
apiScenarioExample.createCriteria().andIdIn(request.getSelectIds());
return apiScenarioMapper.selectByExample(apiScenarioExample);
}
}
public long getAllCount(List<ModuleCountDTO> moduleCountDTOList) {
long count = 0;
for (ModuleCountDTO countDTO : moduleCountDTOList) {
count += countDTO.getDataCount();
}
return count;
}
/**
* 查找当前项目下模块每个节点对应的资源统计
*/
public Map<String, Long> getModuleCountMap(TestCasePageProviderRequest request, List<ModuleCountDTO> moduleCountDTOList) {
//构建模块树并计算每个节点下的所有数量包含子节点
List<BaseTreeNode> treeNodeList = this.getTreeOnlyIdsAndResourceCount(request, moduleCountDTOList);
return apiScenarioModuleService.getIdCountMapByBreadth(treeNodeList);
}
public List<BaseTreeNode> getTreeOnlyIdsAndResourceCount(TestCasePageProviderRequest request, List<ModuleCountDTO> moduleCountDTOList) {
//节点内容只有Id和parentId
List<BaseTreeNode> fileModuleList = extApiScenarioMapper.selectIdAndParentIdByProjectId(request.getProjectId());
return apiScenarioModuleService.buildTreeAndCountResource(fileModuleList, moduleCountDTOList, true, Translator.get(UNPLANNED_SCENARIO));
}
}

View File

@ -0,0 +1,91 @@
package io.metersphere.api.controller;
import io.metersphere.api.domain.ApiScenario;
import io.metersphere.api.provider.AssociateScenarioProvider;
import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@AutoConfigureMockMvc
public class AssociateScenarioProviderTest extends BaseTest {
@Resource
private AssociateScenarioProvider provider;
@Test
@Order(1)
@Sql(scripts = {"/dml/init_functional_scenario_test.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void getScenarioCaseListSuccess() throws Exception {
TestCasePageProviderRequest request = new TestCasePageProviderRequest();
request.setSourceType("SCENARIO");
request.setSourceId("gyq_associate_scenario_id_1");
request.setProjectId("project-associate-scenario-test");
request.setCurrent(1);
request.setPageSize(10);
request.setSort(new HashMap<>() {{
put("createTime", "desc");
}});
List<TestCaseProviderDTO> apiScenarioList = provider.getScenarioCaseList("functional_case_test", "case_id", "source_id", request);
String jsonString = JSON.toJSONString(apiScenarioList);
System.out.println(jsonString);
}
@Test
@Order(2)
public void moduleCountSuccess() throws Exception {
TestCasePageProviderRequest request = new TestCasePageProviderRequest();
request.setSourceType("SCENARIO");
request.setSourceId("gyq_associate_scenario_id_1");
request.setProjectId("project-associate-scenario-test");
request.setCurrent(1);
request.setPageSize(10);
request.setSort(new HashMap<>() {{
put("createTime", "desc");
}});
Map<String, Long> stringLongMap = provider.moduleCount("functional_case_test", "case_id", "source_id", request, false);
String jsonString = JSON.toJSONString(stringLongMap);
System.out.println(jsonString);
}
@Test
@Order(3)
public void getSelectIdsSuccess() throws Exception {
AssociateOtherCaseRequest request = new AssociateOtherCaseRequest();
request.setSourceType("SCENARIO");
request.setSourceId("gyq_associate_scenario_id_1");
request.setSelectAll(true);
request.setProjectId("project-associate-scenario-test");
request.setExcludeIds(List.of("associate_gyq_api_scenario_two"));
List<ApiScenario> scenarioCases = provider.getSelectScenarioCases(request, false);
Assertions.assertTrue(CollectionUtils.isNotEmpty(scenarioCases));
request.setSelectAll(false);
request.setProjectId("project-associate-scenario-test");
request.setSelectIds(List.of("associate_gyq_api_scenario_one"));
scenarioCases = provider.getSelectScenarioCases(request, false);
Assertions.assertTrue(CollectionUtils.isNotEmpty(scenarioCases));
request.setSourceType("SCENARIO");
request.setSourceId("gyq_associate_scenario_id_1");
request.setSelectAll(true);
request.setProjectId("project-associate-scenario-test");
scenarioCases = provider.getSelectScenarioCases(request, false);
Assertions.assertTrue(CollectionUtils.isNotEmpty(scenarioCases));
}
}

View File

@ -0,0 +1,27 @@
INSERT INTO organization(id, num, name, description, create_time, update_time, create_user, update_user, deleted,
delete_user, delete_time) VALUE
('organization-associate-scenario-test', null, 'organization-associate-case-test', 'organization-associate-case-test',
UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'admin', 0, null, null);
INSERT INTO project (id, num, organization_id, name, description, create_user, update_user, create_time, update_time)
VALUES ('project-associate-scenario-test', null, 'organization-associate-scenario-test', '用例评论项目', '系统默认创建的项目',
'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('gyq_associate_scenario_id_1', 100, 'TEST_MODULE_ID', 'project-associate-case-test', '100001', '测试', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'v1.0.0', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('gyq_associate_scenario_id_1', 'STEP', '1111', '', '', 'TEST');
INSERT INTO api_scenario(id, name, priority, status, last_report_status, last_report_id, num, pos, version_id, ref_id, project_id, module_id, description, tags, create_user, create_time, delete_time, delete_user, update_user, update_time, deleted)
VALUES ('associate_gyq_api_scenario_one', 'api_scenario', 'p1', 'test-api-status', null, null,1000001, 1,'v1.10', 'associate_gyq_api_scenario_one','project-associate-scenario-test', 'gyq_associate_test_scenario_module', null,null,'admin', UNIX_TIMESTAMP() * 1000,null,null,'admin', UNIX_TIMESTAMP() * 1000, false),
('associate_gyq_api_scenario_two', 'api_scenario_two', 'p1', 'test-api-status', null, null,1000001, 1,'v1.10', 'associate_gyq_api_scenario_two','project-associate-scenario-test', 'gyq_associate_test_scenario_module', null,null,'admin', UNIX_TIMESTAMP() * 1000,null,null,'admin', UNIX_TIMESTAMP() * 1000, false);
INSERT INTO api_scenario_module(id, name,parent_id, project_id, pos, create_time, update_time, update_user, create_user)
VALUES ('gyq_associate_test_scenario_module', 'gyq_associate_test_module', 'NONE', 'project-associate-scenario-test', 100, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin','admin');
INSERT INTO project_version(id, project_id, name, description, status, latest, publish_time, start_time, end_time, create_time, create_user)
values ('gyq_associate_test_scenario_version_id','project-associate-scenario-test','v1.0.0', null, 'open', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin');

View File

@ -1,5 +1,6 @@
package io.metersphere.functional.service; package io.metersphere.functional.service;
import io.metersphere.api.domain.ApiScenario;
import io.metersphere.api.domain.ApiTestCase; import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.dto.BugProviderDTO; import io.metersphere.dto.BugProviderDTO;
import io.metersphere.dto.TestCaseProviderDTO; import io.metersphere.dto.TestCaseProviderDTO;
@ -17,6 +18,7 @@ import io.metersphere.functional.request.DisassociateOtherCaseRequest;
import io.metersphere.functional.request.FunctionalCaseTestRequest; import io.metersphere.functional.request.FunctionalCaseTestRequest;
import io.metersphere.provider.BaseAssociateApiProvider; import io.metersphere.provider.BaseAssociateApiProvider;
import io.metersphere.provider.BaseAssociateBugProvider; import io.metersphere.provider.BaseAssociateBugProvider;
import io.metersphere.provider.BaseAssociateScenarioProvider;
import io.metersphere.request.*; import io.metersphere.request.*;
import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
@ -32,6 +34,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -44,7 +47,10 @@ import java.util.Map;
public class FunctionalTestCaseService { public class FunctionalTestCaseService {
@Resource @Resource
private BaseAssociateApiProvider provider; private BaseAssociateApiProvider associateApiProvider;
@Resource
private BaseAssociateScenarioProvider associateScenarioProvider;
@Resource @Resource
SqlSessionFactory sqlSessionFactory; SqlSessionFactory sqlSessionFactory;
@ -68,13 +74,19 @@ public class FunctionalTestCaseService {
/** /**
* 获取功能用例未关联的接口用例列表 * 获取功能用例未关联的用例列表
* *
* @param request request * @param request request
* @return List<ApiTestCaseProviderDTO> * @return List<ApiTestCaseProviderDTO>
*/ */
public List<TestCaseProviderDTO> page(TestCasePageProviderRequest request) { public List<TestCaseProviderDTO> page(TestCasePageProviderRequest request) {
return provider.getApiTestCaseList("functional_case_test", "case_id", "source_id", request); List<TestCaseProviderDTO> testCaseProviderDTOS = new ArrayList<>();
switch (request.getSourceType()) {
case AssociateCaseType.API -> testCaseProviderDTOS = associateApiProvider.getApiTestCaseList("functional_case_test", "case_id", "source_id", request);
case AssociateCaseType.SCENARIO -> testCaseProviderDTOS = associateScenarioProvider.getScenarioCaseList("functional_case_test", "case_id", "source_id", request);
default -> new ArrayList<>();
}
return testCaseProviderDTOS;
} }
/** /**
@ -85,7 +97,13 @@ public class FunctionalTestCaseService {
* @return 接口模块统计数量 * @return 接口模块统计数量
*/ */
public Map<String, Long> moduleCount(TestCasePageProviderRequest request, boolean deleted) { public Map<String, Long> moduleCount(TestCasePageProviderRequest request, boolean deleted) {
return provider.moduleCount("functional_case_test", "case_id", "source_id", request, deleted); Map<String, Long> moduleCount = new HashMap<>();
switch (request.getSourceType()) {
case AssociateCaseType.API -> moduleCount = associateApiProvider.moduleCount("functional_case_test", "case_id", "source_id", request, deleted);
case AssociateCaseType.SCENARIO -> moduleCount = associateScenarioProvider.moduleCount("functional_case_test", "case_id", "source_id", request, deleted);
default -> new HashMap<>();
}
return moduleCount;
} }
@ -96,22 +114,41 @@ public class FunctionalTestCaseService {
* @param deleted 接口定义是否删除 * @param deleted 接口定义是否删除
*/ */
public void associateCase(AssociateOtherCaseRequest request, boolean deleted, String userId) { public void associateCase(AssociateOtherCaseRequest request, boolean deleted, String userId) {
switch (request.getSourceType()) { switch (request.getSourceType()) {
case AssociateCaseType.API -> associateApi(request, deleted, userId); case AssociateCaseType.API -> associateApi(request, deleted, userId);
case AssociateCaseType.SCENARIO -> associateScenario(request, deleted, userId); case AssociateCaseType.SCENARIO -> associateScenario(request, deleted, userId);
default -> LogUtils.info("AssociateCaseType: " + request.getSourceType()); default -> LogUtils.info("AssociateCaseType: " + request.getSourceType());
} }
} }
private void associateScenario(AssociateOtherCaseRequest request, boolean deleted, String userId) { private void associateScenario(AssociateOtherCaseRequest request, boolean deleted, String userId) {
List<ApiScenario> scenarioCases = associateScenarioProvider.getSelectScenarioCases(request, deleted);
if (CollectionUtils.isEmpty(scenarioCases)) {
return;
}
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
FunctionalCaseTestMapper caseTestMapper = sqlSession.getMapper(FunctionalCaseTestMapper.class);
for (ApiScenario apiScenario : scenarioCases) {
FunctionalCaseTest functionalCaseTest = new FunctionalCaseTest();
functionalCaseTest.setCaseId(request.getSourceId());
functionalCaseTest.setProjectId(request.getProjectId());
functionalCaseTest.setSourceId(apiScenario.getId());
functionalCaseTest.setVersionId(apiScenario.getVersionId());
functionalCaseTest.setSourceType(request.getSourceType());
functionalCaseTest.setId(IdGenerator.random().generateId());
functionalCaseTest.setCreateUser(userId);
functionalCaseTest.setCreateTime(System.currentTimeMillis());
functionalCaseTest.setUpdateUser(userId);
functionalCaseTest.setUpdateTime(System.currentTimeMillis());
caseTestMapper.insert(functionalCaseTest);
}
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
LogUtils.info("关联场景"); LogUtils.info("关联场景");
} }
private void associateApi(AssociateOtherCaseRequest request, boolean deleted, String userId) { private void associateApi(AssociateOtherCaseRequest request, boolean deleted, String userId) {
List<ApiTestCase> apiTestCases = provider.getSelectApiTestCases(request, deleted); List<ApiTestCase> apiTestCases = associateApiProvider.getSelectApiTestCases(request, deleted);
if (CollectionUtils.isEmpty(apiTestCases)) { if (CollectionUtils.isEmpty(apiTestCases)) {
return; return;
} }

View File

@ -2,6 +2,7 @@ package io.metersphere.functional.config;
import io.metersphere.provider.BaseAssociateApiProvider; import io.metersphere.provider.BaseAssociateApiProvider;
import io.metersphere.provider.BaseAssociateBugProvider; import io.metersphere.provider.BaseAssociateBugProvider;
import io.metersphere.provider.BaseAssociateScenarioProvider;
import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
@ -11,6 +12,9 @@ public class CaseTestConfiguration {
@MockBean @MockBean
BaseAssociateApiProvider provider; BaseAssociateApiProvider provider;
@MockBean
BaseAssociateScenarioProvider scenarioProvider;
@MockBean @MockBean
BaseAssociateBugProvider baseAssociateBugProvider; BaseAssociateBugProvider baseAssociateBugProvider;

View File

@ -1,8 +1,10 @@
package io.metersphere.functional.controller; package io.metersphere.functional.controller;
import io.metersphere.api.domain.ApiDefinitionModule; import io.metersphere.api.domain.ApiDefinitionModule;
import io.metersphere.api.domain.ApiScenarioModule;
import io.metersphere.api.domain.ApiTestCase; import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.api.mapper.ApiDefinitionModuleMapper; import io.metersphere.api.mapper.ApiDefinitionModuleMapper;
import io.metersphere.api.mapper.ApiScenarioModuleMapper;
import io.metersphere.dto.BugProviderDTO; import io.metersphere.dto.BugProviderDTO;
import io.metersphere.dto.TestCaseProviderDTO; import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.functional.constants.AssociateCaseType; import io.metersphere.functional.constants.AssociateCaseType;
@ -17,10 +19,9 @@ import io.metersphere.functional.request.AssociateCaseModuleRequest;
import io.metersphere.functional.request.AssociatePlanPageRequest; import io.metersphere.functional.request.AssociatePlanPageRequest;
import io.metersphere.functional.request.DisassociateOtherCaseRequest; import io.metersphere.functional.request.DisassociateOtherCaseRequest;
import io.metersphere.functional.request.FunctionalCaseTestRequest; import io.metersphere.functional.request.FunctionalCaseTestRequest;
import io.metersphere.plan.mapper.TestPlanFunctionalCaseMapper;
import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.provider.BaseAssociateApiProvider; import io.metersphere.provider.BaseAssociateApiProvider;
import io.metersphere.provider.BaseAssociateBugProvider; import io.metersphere.provider.BaseAssociateBugProvider;
import io.metersphere.provider.BaseAssociateScenarioProvider;
import io.metersphere.request.*; import io.metersphere.request.*;
import io.metersphere.sdk.constants.FunctionalCaseExecuteResult; import io.metersphere.sdk.constants.FunctionalCaseExecuteResult;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
@ -72,6 +73,9 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
@Resource @Resource
BaseAssociateApiProvider provider; BaseAssociateApiProvider provider;
@Resource
BaseAssociateScenarioProvider scenarioProvider;
@Resource @Resource
private FunctionalCaseTestMapper functionalCaseTestMapper; private FunctionalCaseTestMapper functionalCaseTestMapper;
@ -80,17 +84,16 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
@Resource @Resource
private ApiDefinitionModuleMapper apiDefinitionModuleMapper; private ApiDefinitionModuleMapper apiDefinitionModuleMapper;
@Resource
private ApiScenarioModuleMapper apiScenarioModuleMapper;
@Resource @Resource
BaseAssociateBugProvider baseAssociateBugProvider; BaseAssociateBugProvider baseAssociateBugProvider;
@Resource
TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper;
@Resource
TestPlanMapper testPlanMapper;
@Test @Test
@Order(1) @Order(1)
@Sql(scripts = {"/dml/init_test_plan_case.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void getPageSuccess() throws Exception { public void getPageSuccess() throws Exception {
TestCasePageProviderRequest request = new TestCasePageProviderRequest(); TestCasePageProviderRequest request = new TestCasePageProviderRequest();
request.setSourceType(AssociateCaseType.API); request.setSourceType(AssociateCaseType.API);
@ -114,6 +117,27 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
Assertions.assertNotNull(testCaseProviderDTOS); Assertions.assertNotNull(testCaseProviderDTOS);
System.out.println(JSON.toJSONString(apiTestCaseList)); System.out.println(JSON.toJSONString(apiTestCaseList));
request = new TestCasePageProviderRequest();
request.setSourceType(AssociateCaseType.SCENARIO);
request.setSourceId("gyq_associate_scenario_id_1");
request.setProjectId("project_gyq_associate_test");
request.setCurrent(1);
request.setPageSize(10);
request.setSort(new HashMap<>() {{
put("createTime", "desc");
}});
testCaseProviderDTO = new TestCaseProviderDTO();
testCaseProviderDTO.setName("第一个场景");
operations = new ArrayList<>();
operations.add(testCaseProviderDTO);
Mockito.when(scenarioProvider.getScenarioCaseList("functional_case_test", "case_id", "source_id", request)).thenReturn(operations);
List<TestCaseProviderDTO> apiScenarioList = scenarioProvider.getScenarioCaseList("functional_case_test", "case_id", "source_id", request);
mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE, request);
returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
testCaseProviderDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), TestCaseProviderDTO.class);
Assertions.assertNotNull(testCaseProviderDTOS);
System.out.println(JSON.toJSONString(apiScenarioList));
} }
@Test @Test
@ -133,6 +157,20 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
Assertions.assertNotNull(testCaseProviderDTOS); Assertions.assertNotNull(testCaseProviderDTOS);
System.out.println(JSON.toJSONString(apiTestCaseList)); System.out.println(JSON.toJSONString(apiTestCaseList));
request = new TestCasePageProviderRequest();
request.setSourceType(AssociateCaseType.SCENARIO);
request.setSourceId("gyq_associate_scenario_id_1");
request.setProjectId("project_gyq_associate_test");
request.setCurrent(1);
request.setPageSize(10);
List<TestCaseProviderDTO> apiScenarioList = scenarioProvider.getScenarioCaseList("functional_case_test", "case_id", "source_id", request);
mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE, request);
returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
testCaseProviderDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), TestCaseProviderDTO.class);
Assertions.assertNotNull(testCaseProviderDTOS);
System.out.println(JSON.toJSONString(apiScenarioList));
} }
@Test @Test
@ -148,6 +186,17 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Assertions.assertNotNull(resultHolder); Assertions.assertNotNull(resultHolder);
TestCasePageProviderRequest scenarioRequest = new TestCasePageProviderRequest();
scenarioRequest.setSourceType(AssociateCaseType.SCENARIO);
scenarioRequest.setSourceId("gyq_associate_scenario_id_1");
scenarioRequest.setProjectId("project_gyq_associate_test");
scenarioRequest.setCurrent(1);
request.setPageSize(10);
mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_MODULE_COUNT, request);
returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Assertions.assertNotNull(resultHolder);
} }
@Test @Test
@ -226,6 +275,38 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class); resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Assertions.assertNotNull(resultHolder); Assertions.assertNotNull(resultHolder);
addFunctionalCaseScenarioTest();
request = new DisassociateOtherCaseRequest();
request.setSourceType(AssociateCaseType.SCENARIO);
request.setCaseId("gyq_associate_functional_case_id_1");
request.setSelectAll(true);
request.setExcludeIds(List.of("gyq_associate_api_scenario_id_2"));
mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_DISASSOCIATE, request);
returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Assertions.assertNotNull(resultHolder);
functionalCaseTest = functionalCaseTestMapper.selectByPrimaryKey("functionalCaseTestHasScenarioId");
Assertions.assertNull(functionalCaseTest);
request = new DisassociateOtherCaseRequest();
request.setSourceType(AssociateCaseType.API);
request.setCaseId("gyq_associate_case_id_1");
request.setSelectAll(true);
request.setSelectIds(List.of("gyq_associate_api_scenario_id_1"));
mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_DISASSOCIATE, request);
returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Assertions.assertNotNull(resultHolder);
request = new DisassociateOtherCaseRequest();
request.setSourceType(AssociateCaseType.SCENARIO);
request.setCaseId("gyq_associate_case_id_1");
request.setSelectAll(false);
request.setSelectIds(List.of("gyq_associate_api_scenario_id_1"));
mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_DISASSOCIATE, request);
returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Assertions.assertNotNull(resultHolder);
} }
@Test @Test
@ -244,6 +325,19 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
apiDefinitionModuleMapper.insert(apiDefinitionModule); apiDefinitionModuleMapper.insert(apiDefinitionModule);
List<BaseTreeNode> moduleTreeNode = this.getModuleTreeNode(); List<BaseTreeNode> moduleTreeNode = this.getModuleTreeNode();
Assertions.assertNotNull(moduleTreeNode); Assertions.assertNotNull(moduleTreeNode);
ApiScenarioModule apiScenarioModule = new ApiScenarioModule();
apiScenarioModule.setId("scenario_module");
apiScenarioModule.setPos(100L);
apiScenarioModule.setName("api_scenario_module");
apiScenarioModule.setParentId("NONE");
apiScenarioModule.setProjectId("project-associate-case-test");
apiScenarioModule.setCreateUser("admin");
apiScenarioModule.setCreateTime(System.currentTimeMillis());
apiScenarioModule.setUpdateUser("admin");
apiScenarioModule.setUpdateTime(System.currentTimeMillis());
apiScenarioModuleMapper.insert(apiScenarioModule);
List<BaseTreeNode> moduleScenarioTreeNode = this.getModuleScenarioTreeNode();
Assertions.assertNotNull(moduleScenarioTreeNode);
} }
@Test @Test
@ -262,6 +356,19 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
// 返回值中取出第一条ID最大的数据, 并判断是否是default-admin // 返回值中取出第一条ID最大的数据, 并判断是否是default-admin
List<FunctionalCaseTestDTO> functionalCaseTestDTOS = JSON.parseArray(JSON.toJSONString(sortPageData.getList()), FunctionalCaseTestDTO.class); List<FunctionalCaseTestDTO> functionalCaseTestDTOS = JSON.parseArray(JSON.toJSONString(sortPageData.getList()), FunctionalCaseTestDTO.class);
Assertions.assertNotNull(functionalCaseTestDTOS); Assertions.assertNotNull(functionalCaseTestDTOS);
addFunctionalCaseScenarioTest();
request = new FunctionalCaseTestRequest();
request.setSourceType(AssociateCaseType.SCENARIO);
request.setSourceId("gyq_associate_functional_case_id_1");
request.setCurrent(1);
request.setPageSize(10);
mvcResult = this.requestPostWithOkAndReturn(URL_HAS_CASE_PAGE, request);
sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
sortHolder = JSON.parseObject(sortData, ResultHolder.class);
sortPageData = JSON.parseObject(JSON.toJSONString(sortHolder.getData()), Pager.class);
// 返回值中取出第一条ID最大的数据, 并判断是否是default-admin
functionalCaseTestDTOS = JSON.parseArray(JSON.toJSONString(sortPageData.getList()), FunctionalCaseTestDTO.class);
Assertions.assertNotNull(functionalCaseTestDTOS);
} }
@ -276,6 +383,16 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
return JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BaseTreeNode.class); return JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BaseTreeNode.class);
} }
private List<BaseTreeNode> getModuleScenarioTreeNode() throws Exception {
MvcResult result = this.requestPostWithOkAndReturn(URL_CASE_MODULE_TREE, new AssociateCaseModuleRequest() {{
this.setProjectId("project-associate-case-test");
this.setSourceType(AssociateCaseType.SCENARIO);
}});
String returnData = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
return JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BaseTreeNode.class);
}
private void addFunctionalCaseTest() { private void addFunctionalCaseTest() {
FunctionalCaseTest functionalCaseTest = new FunctionalCaseTest(); FunctionalCaseTest functionalCaseTest = new FunctionalCaseTest();
functionalCaseTest.setId("functionalCaseTestHasId"); functionalCaseTest.setId("functionalCaseTestHasId");
@ -291,6 +408,21 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
functionalCaseTestMapper.insert(functionalCaseTest); functionalCaseTestMapper.insert(functionalCaseTest);
} }
private void addFunctionalCaseScenarioTest() {
FunctionalCaseTest functionalCaseTest = new FunctionalCaseTest();
functionalCaseTest.setId("functionalCaseTestHasScenarioId");
functionalCaseTest.setCaseId("gyq_associate_functional_case_id_1");
functionalCaseTest.setVersionId("1.0");
functionalCaseTest.setSourceId("gyq_api_scenario_id_1");
functionalCaseTest.setSourceType(AssociateCaseType.SCENARIO);
functionalCaseTest.setProjectId("gyq-organization-associate-case-test");
functionalCaseTest.setCreateUser("admin");
functionalCaseTest.setCreateTime(System.currentTimeMillis());
functionalCaseTest.setUpdateUser("admin");
functionalCaseTest.setUpdateTime(System.currentTimeMillis());
functionalCaseTestMapper.insert(functionalCaseTest);
}
private void addFunctionalCase() { private void addFunctionalCase() {
FunctionalCase functionalCase = new FunctionalCase(); FunctionalCase functionalCase = new FunctionalCase();
functionalCase.setName("测试关联"); functionalCase.setName("测试关联");
@ -401,6 +533,7 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
@Test @Test
@Order(12) @Order(12)
@Sql(scripts = {"/dml/init_test_plan_case.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void testAssociatePlanPage() throws Exception { public void testAssociatePlanPage() throws Exception {
AssociatePlanPageRequest request = new AssociatePlanPageRequest(); AssociatePlanPageRequest request = new AssociatePlanPageRequest();
request.setCurrent(1); request.setCurrent(1);