feat(功能用例): 新增功能用例获取关联用例列表

This commit is contained in:
guoyuqi 2024-01-02 18:44:52 +08:00 committed by Craftsman
parent a81a8cba2b
commit 6682e53cca
22 changed files with 324 additions and 95 deletions

View File

@ -35,6 +35,11 @@ public class FunctionalCaseTest implements Serializable {
@Size(min = 1, max = 50, message = "{functional_case_test.project_id.length_range}", groups = {Created.class, Updated.class})
private String projectId;
@Schema(description = "用例的版本id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{functional_case_test.version_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{functional_case_test.version_id.length_range}", groups = {Created.class, Updated.class})
private String versionId;
@Schema(description = "创建时间")
private Long createTime;
@ -55,6 +60,7 @@ public class FunctionalCaseTest implements Serializable {
sourceId("source_id", "sourceId", "VARCHAR", false),
sourceType("source_type", "sourceType", "VARCHAR", false),
projectId("project_id", "projectId", "VARCHAR", false),
versionId("version_id", "versionId", "VARCHAR", false),
createTime("create_time", "createTime", "BIGINT", false),
updateTime("update_time", "updateTime", "BIGINT", false),
createUser("create_user", "createUser", "VARCHAR", false),

View File

@ -454,6 +454,76 @@ public class FunctionalCaseTestExample {
return (Criteria) this;
}
public Criteria andVersionIdIsNull() {
addCriterion("version_id is null");
return (Criteria) this;
}
public Criteria andVersionIdIsNotNull() {
addCriterion("version_id is not null");
return (Criteria) this;
}
public Criteria andVersionIdEqualTo(String value) {
addCriterion("version_id =", value, "versionId");
return (Criteria) this;
}
public Criteria andVersionIdNotEqualTo(String value) {
addCriterion("version_id <>", value, "versionId");
return (Criteria) this;
}
public Criteria andVersionIdGreaterThan(String value) {
addCriterion("version_id >", value, "versionId");
return (Criteria) this;
}
public Criteria andVersionIdGreaterThanOrEqualTo(String value) {
addCriterion("version_id >=", value, "versionId");
return (Criteria) this;
}
public Criteria andVersionIdLessThan(String value) {
addCriterion("version_id <", value, "versionId");
return (Criteria) this;
}
public Criteria andVersionIdLessThanOrEqualTo(String value) {
addCriterion("version_id <=", value, "versionId");
return (Criteria) this;
}
public Criteria andVersionIdLike(String value) {
addCriterion("version_id like", value, "versionId");
return (Criteria) this;
}
public Criteria andVersionIdNotLike(String value) {
addCriterion("version_id not like", value, "versionId");
return (Criteria) this;
}
public Criteria andVersionIdIn(List<String> values) {
addCriterion("version_id in", values, "versionId");
return (Criteria) this;
}
public Criteria andVersionIdNotIn(List<String> values) {
addCriterion("version_id not in", values, "versionId");
return (Criteria) this;
}
public Criteria andVersionIdBetween(String value1, String value2) {
addCriterion("version_id between", value1, value2, "versionId");
return (Criteria) this;
}
public Criteria andVersionIdNotBetween(String value1, String value2) {
addCriterion("version_id not between", value1, value2, "versionId");
return (Criteria) this;
}
public Criteria andCreateTimeIsNull() {
addCriterion("create_time is null");
return (Criteria) this;

View File

@ -7,6 +7,7 @@
<result column="source_id" jdbcType="VARCHAR" property="sourceId" />
<result column="source_type" jdbcType="VARCHAR" property="sourceType" />
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
<result column="version_id" jdbcType="VARCHAR" property="versionId" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
@ -71,8 +72,8 @@
</where>
</sql>
<sql id="Base_Column_List">
id, case_id, source_id, source_type, project_id, create_time, update_time, create_user,
update_user
id, case_id, source_id, source_type, project_id, version_id, create_time, update_time,
create_user, update_user
</sql>
<select id="selectByExample" parameterType="io.metersphere.functional.domain.FunctionalCaseTestExample" resultMap="BaseResultMap">
select
@ -106,13 +107,13 @@
</delete>
<insert id="insert" parameterType="io.metersphere.functional.domain.FunctionalCaseTest">
insert into functional_case_test (id, case_id, source_id,
source_type, project_id, create_time,
update_time, create_user, update_user
)
source_type, project_id, version_id,
create_time, update_time, create_user,
update_user)
values (#{id,jdbcType=VARCHAR}, #{caseId,jdbcType=VARCHAR}, #{sourceId,jdbcType=VARCHAR},
#{sourceType,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
#{updateTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR}, #{updateUser,jdbcType=VARCHAR}
)
#{sourceType,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{versionId,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR},
#{updateUser,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.functional.domain.FunctionalCaseTest">
insert into functional_case_test
@ -132,6 +133,9 @@
<if test="projectId != null">
project_id,
</if>
<if test="versionId != null">
version_id,
</if>
<if test="createTime != null">
create_time,
</if>
@ -161,6 +165,9 @@
<if test="projectId != null">
#{projectId,jdbcType=VARCHAR},
</if>
<if test="versionId != null">
#{versionId,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
@ -199,6 +206,9 @@
<if test="record.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR},
</if>
<if test="record.versionId != null">
version_id = #{record.versionId,jdbcType=VARCHAR},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
@ -223,6 +233,7 @@
source_id = #{record.sourceId,jdbcType=VARCHAR},
source_type = #{record.sourceType,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR},
version_id = #{record.versionId,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
create_user = #{record.createUser,jdbcType=VARCHAR},
@ -246,6 +257,9 @@
<if test="projectId != null">
project_id = #{projectId,jdbcType=VARCHAR},
</if>
<if test="versionId != null">
version_id = #{versionId,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
@ -267,6 +281,7 @@
source_id = #{sourceId,jdbcType=VARCHAR},
source_type = #{sourceType,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR},
version_id = #{versionId,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
create_user = #{createUser,jdbcType=VARCHAR},
@ -275,14 +290,14 @@
</update>
<insert id="batchInsert" parameterType="map">
insert into functional_case_test
(id, case_id, source_id, source_type, project_id, create_time, update_time, create_user,
update_user)
(id, case_id, source_id, source_type, project_id, version_id, create_time, update_time,
create_user, update_user)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.caseId,jdbcType=VARCHAR}, #{item.sourceId,jdbcType=VARCHAR},
#{item.sourceType,jdbcType=VARCHAR}, #{item.projectId,jdbcType=VARCHAR}, #{item.createTime,jdbcType=BIGINT},
#{item.updateTime,jdbcType=BIGINT}, #{item.createUser,jdbcType=VARCHAR}, #{item.updateUser,jdbcType=VARCHAR}
)
#{item.sourceType,jdbcType=VARCHAR}, #{item.projectId,jdbcType=VARCHAR}, #{item.versionId,jdbcType=VARCHAR},
#{item.createTime,jdbcType=BIGINT}, #{item.updateTime,jdbcType=BIGINT}, #{item.createUser,jdbcType=VARCHAR},
#{item.updateUser,jdbcType=VARCHAR})
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
@ -310,6 +325,9 @@
<if test="'project_id'.toString() == column.value">
#{item.projectId,jdbcType=VARCHAR}
</if>
<if test="'version_id'.toString() == column.value">
#{item.versionId,jdbcType=VARCHAR}
</if>
<if test="'create_time'.toString() == column.value">
#{item.createTime,jdbcType=BIGINT}
</if>

View File

@ -164,6 +164,7 @@ CREATE TABLE IF NOT EXISTS functional_case_test
`source_id` VARCHAR(50) NOT NULL COMMENT '其他类型用例ID',
`source_type` VARCHAR(64) NOT NULL COMMENT '用例类型:接口用例/场景用例/性能用例/UI用例',
`project_id` VARCHAR(50) NOT NULL COMMENT '用例所属项目' ,
`version_id` VARCHAR(50) NOT NULL COMMENT '用例的版本id' ,
`create_time` BIGINT NOT NULL COMMENT '创建时间',
`update_time` BIGINT NOT NULL COMMENT '更新时间',
`create_user` VARCHAR(50) NOT NULL COMMENT '创建人',

View File

@ -1,9 +1,10 @@
package io.metersphere.provider;
import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.request.ApiModuleProviderRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.request.AssociateCaseModuleProviderRequest;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import java.util.List;
import java.util.Map;
@ -30,14 +31,14 @@ public interface BaseAssociateApiProvider {
* @param deleted 接口定义是否删除
* @return 接口模块统计数量
*/
Map<String, Long> moduleCount(String sourceType, String sourceName, String apiCaseColumnName, ApiModuleProviderRequest request, boolean deleted);
Map<String, Long> moduleCount(String sourceType, String sourceName, String apiCaseColumnName, AssociateCaseModuleProviderRequest request, boolean deleted);
/**
* 根据页面筛选条件获取批量操作的用例ids
* 根据页面筛选条件获取批量操作的用例
*
* @return 接口用例的ids
*/
List<String> getSelectIds(AssociateOtherCaseRequest request, Boolean deleted);
List<ApiTestCase> getSelectApiTestCases(AssociateOtherCaseRequest request, Boolean deleted);
}

View File

@ -9,7 +9,7 @@ import lombok.Data;
import java.util.List;
@Data
public class ApiModuleProviderRequest {
public class AssociateCaseModuleProviderRequest {
@Schema(description = "关联关系表里主ID eg:功能用例关联接口用例时为功能用例id")
@NotBlank(message = "{api_definition.project_id.not_blank}")

View File

@ -4,7 +4,7 @@ import io.metersphere.api.dto.debug.ApiTreeNode;
import io.metersphere.api.dto.definition.ApiModuleRequest;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.NodeSortQueryParam;
import io.metersphere.request.ApiModuleProviderRequest;
import io.metersphere.request.AssociateCaseModuleProviderRequest;
import io.metersphere.system.dto.sdk.BaseModule;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import org.apache.ibatis.annotations.Param;
@ -36,7 +36,7 @@ public interface ExtApiDefinitionModuleMapper {
List<BaseTreeNode> selectBaseByIds(@Param("ids") List<String> ids);
List<ModuleCountDTO> countModuleIdByProviderRequest(@Param("table") String resourceType, @Param("sourceName") String sourceName, @Param("apiCaseColumnName") String apiCaseColumnName, @Param("request") ApiModuleProviderRequest request, @Param("deleted") boolean deleted);
List<ModuleCountDTO> countModuleIdByProviderRequest(@Param("table") String resourceType, @Param("sourceName") String sourceName, @Param("apiCaseColumnName") String apiCaseColumnName, @Param("request") AssociateCaseModuleProviderRequest request, @Param("deleted") boolean deleted);
List<BaseTreeNode> selectIdAndParentIdByProviderRequest(@Param("request") ApiModuleProviderRequest request);
List<BaseTreeNode> selectIdAndParentIdByProviderRequest(@Param("request") AssociateCaseModuleProviderRequest request);
}

View File

@ -47,7 +47,7 @@ public interface ExtApiTestCaseMapper {
List<TestCaseProviderDTO> listByProviderRequest(@Param("table") String resourceType, @Param("sourceName") String sourceName, @Param("apiCaseColumnName") String apiCaseColumnName, @Param("request") TestCasePageProviderRequest request, @Param("deleted") boolean deleted);
List<String> getIdsByProvider(@Param("request") AssociateOtherCaseRequest request, @Param("deleted") boolean deleted);
List<ApiTestCase> getTestCaseByProvider(@Param("request") AssociateOtherCaseRequest request, @Param("deleted") boolean deleted);
}

View File

@ -173,9 +173,9 @@
<include refid="queryWhereCondition"/>
</select>
<select id="getIdsByProvider" resultType="java.lang.String">
<select id="getTestCaseByProvider" resultType="io.metersphere.api.domain.ApiTestCase">
SELECT
t1.id
t1.id, t1.version_id
FROM
api_test_case t1
LEFT JOIN api_report t3 ON t1.last_report_id = t3.id

View File

@ -1,14 +1,17 @@
package io.metersphere.api.provider;
import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.api.domain.ApiTestCaseExample;
import io.metersphere.api.mapper.ApiTestCaseMapper;
import io.metersphere.api.mapper.ExtApiDefinitionModuleMapper;
import io.metersphere.api.mapper.ExtApiTestCaseMapper;
import io.metersphere.api.service.definition.ApiDefinitionModuleService;
import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.provider.BaseAssociateApiProvider;
import io.metersphere.request.ApiModuleProviderRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.request.AssociateCaseModuleProviderRequest;
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;
@ -30,6 +33,9 @@ public class AssociateApiProvider implements BaseAssociateApiProvider {
@Resource
private ApiDefinitionModuleService moduleTreeService;
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
private static final String DEBUG_MODULE_COUNT_ALL = "all";
private static final String UNPLANNED_API = "api_unplanned_request";
@ -39,7 +45,7 @@ public class AssociateApiProvider implements BaseAssociateApiProvider {
}
@Override
public Map<String, Long> moduleCount(String sourceType, String sourceName, String apiCaseColumnName, ApiModuleProviderRequest request, boolean deleted) {
public Map<String, Long> moduleCount(String sourceType, String sourceName, String apiCaseColumnName, AssociateCaseModuleProviderRequest request, boolean deleted) {
request.setModuleIds(null);
//查找根据moduleIds查找模块下的接口数量 查非delete状态的
List<ModuleCountDTO> moduleCountDTOList = extApiDefinitionModuleMapper.countModuleIdByProviderRequest(sourceType, sourceName, apiCaseColumnName, request, deleted);
@ -50,15 +56,17 @@ public class AssociateApiProvider implements BaseAssociateApiProvider {
}
@Override
public List<String> getSelectIds(AssociateOtherCaseRequest request, Boolean deleted) {
public List<ApiTestCase> getSelectApiTestCases(AssociateOtherCaseRequest request, Boolean deleted) {
if (request.isSelectAll()) {
List<String> ids = extApiTestCaseMapper.getIdsByProvider(request, deleted);
List<ApiTestCase> cases = extApiTestCaseMapper.getTestCaseByProvider(request, deleted);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
ids.removeAll(request.getExcludeIds());
cases = cases.stream().filter(t -> !request.getExcludeIds().contains(t.getId())).toList();
}
return ids;
return cases;
} else {
return request.getSelectIds();
ApiTestCaseExample apiTestCaseExample = new ApiTestCaseExample();
apiTestCaseExample.createCriteria().andIdIn(request.getSelectIds());
return apiTestCaseMapper.selectByExample(apiTestCaseExample);
}
}
@ -73,13 +81,13 @@ public class AssociateApiProvider implements BaseAssociateApiProvider {
/**
* 查找当前项目下模块每个节点对应的资源统计
*/
public Map<String, Long> getModuleCountMap(ApiModuleProviderRequest request, List<ModuleCountDTO> moduleCountDTOList) {
public Map<String, Long> getModuleCountMap(AssociateCaseModuleProviderRequest request, List<ModuleCountDTO> moduleCountDTOList) {
//构建模块树并计算每个节点下的所有数量包含子节点
List<BaseTreeNode> treeNodeList = this.getTreeOnlyIdsAndResourceCount(request, moduleCountDTOList);
return moduleTreeService.getIdCountMapByBreadth(treeNodeList);
}
public List<BaseTreeNode> getTreeOnlyIdsAndResourceCount(ApiModuleProviderRequest request, List<ModuleCountDTO> moduleCountDTOList) {
public List<BaseTreeNode> getTreeOnlyIdsAndResourceCount(AssociateCaseModuleProviderRequest request, List<ModuleCountDTO> moduleCountDTOList) {
//节点内容只有Id和parentId
List<BaseTreeNode> fileModuleList = extApiDefinitionModuleMapper.selectIdAndParentIdByProviderRequest(request);
return moduleTreeService.buildTreeAndCountResource(fileModuleList, moduleCountDTOList, true, Translator.get(UNPLANNED_API));

View File

@ -1,8 +1,9 @@
package io.metersphere.api.controller;
import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.api.provider.AssociateApiProvider;
import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.request.ApiModuleProviderRequest;
import io.metersphere.request.AssociateCaseModuleProviderRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.sdk.util.JSON;
@ -47,7 +48,7 @@ public class AssociateApiProviderTest extends BaseTest {
@Test
@Order(2)
public void moduleCountSuccess() throws Exception {
ApiModuleProviderRequest request = new ApiModuleProviderRequest();
AssociateCaseModuleProviderRequest request = new AssociateCaseModuleProviderRequest();
request.setSourceId("gyq_associate_case_id_1");
request.setProjectId("project-associate-case-test");
request.setKeyword("测试查询模块用");
@ -66,19 +67,19 @@ public class AssociateApiProviderTest extends BaseTest {
request.setSelectAll(true);
request.setProjectId("project-associate-case-test");
request.setExcludeIds(List.of("gyq_associate_api_case_id_2"));
List<String> selectIds = provider.getSelectIds(request, false);
Assertions.assertTrue(CollectionUtils.isNotEmpty(selectIds));
List<ApiTestCase> apiTestCases = provider.getSelectApiTestCases(request, false);
Assertions.assertTrue(CollectionUtils.isNotEmpty(apiTestCases));
request.setSelectAll(false);
request.setProjectId("project-associate-case-test");
request.setSelectIds(List.of("gyq_associate_api_case_id_1"));
selectIds = provider.getSelectIds(request, false);
Assertions.assertTrue(CollectionUtils.isNotEmpty(selectIds));
apiTestCases = provider.getSelectApiTestCases(request, false);
Assertions.assertTrue(CollectionUtils.isNotEmpty(apiTestCases));
request.setSourceType("API");
request.setSourceId("gyq_associate_case_id_1");
request.setSelectAll(true);
request.setProjectId("project-associate-case-test");
selectIds = provider.getSelectIds(request, false);
Assertions.assertTrue(CollectionUtils.isNotEmpty(selectIds));
apiTestCases = provider.getSelectApiTestCases(request, false);
Assertions.assertTrue(CollectionUtils.isNotEmpty(apiTestCases));
}

View File

@ -51,7 +51,7 @@ public class CaseReviewController {
}
@PostMapping("/module/count")
@Operation(summary = "用例管理-用例评审-表格分页查询文件")
@Operation(summary = "用例管理-用例评审-获取模块树统计数量")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public Map<String, Long> moduleCount(@Validated @RequestBody CaseReviewPageRequest request) {
@ -147,7 +147,7 @@ public class CaseReviewController {
caseReviewService.batchMoveCaseReview(request, SessionUtils.getUserId());
}
@GetMapping("/delete/{reviewId}/{projectId}")
@GetMapping("/delete/{projectId}/{reviewId}")
@Operation(summary = "用例管理-用例评审-删除用例评审")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_DELETE)
@SendNotice(taskType = NoticeConstants.TaskType.CASE_REVIEW_TASK, event = NoticeConstants.Event.DELETE, target = "#targetClass.getMainCaseReview(#reviewId)", targetClass = CaseReviewNoticeService.class)

View File

@ -3,10 +3,12 @@ package io.metersphere.functional.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.functional.request.CaseApiModuleRequest;
import io.metersphere.functional.request.FunctionalTestCaseDisassociateRequest;
import io.metersphere.functional.dto.FunctionalCaseTestDTO;
import io.metersphere.functional.request.AssociateCaseModuleRequest;
import io.metersphere.functional.request.DisassociateOtherCaseRequest;
import io.metersphere.functional.request.FunctionalCaseTestRequest;
import io.metersphere.functional.service.FunctionalTestCaseService;
import io.metersphere.request.ApiModuleProviderRequest;
import io.metersphere.request.AssociateCaseModuleProviderRequest;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.sdk.constants.PermissionConstants;
@ -38,29 +40,29 @@ public class FunctionalTestCaseController {
@Resource
private FunctionalTestCaseService functionalTestCaseService;
@PostMapping("/associate/api/page")
@Operation(summary = "用例管理-功能用例-关联其他用例-获取接口用例列表")
@PostMapping("/associate/case/page")
@Operation(summary = "用例管理-功能用例-关联其他用例-获取需要关联的用例列表")
@RequiresPermissions(value = {PermissionConstants.FUNCTIONAL_CASE_READ_ADD, PermissionConstants.FUNCTIONAL_CASE_READ_UPDATE, PermissionConstants.FUNCTIONAL_CASE_READ_DELETE}, logical = Logical.OR)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public Pager<List<TestCaseProviderDTO>> associateApiCaseList(@Validated @RequestBody TestCasePageProviderRequest request) {
public Pager<List<TestCaseProviderDTO>> associateOtherCaseList(@Validated @RequestBody TestCasePageProviderRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "create_time desc");
return PageUtils.setPageInfo(page, functionalTestCaseService.page(request));
}
@PostMapping("/associate/api/module/count")
@Operation(summary = "用例管理-功能用例-关联其他用例-统计接口用例模块数量")
@PostMapping("/associate/case/module/count")
@Operation(summary = "用例管理-功能用例-关联其他用例-统计需要关联用例模块数量")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
@CheckOwner(resourceId = "#request.projectId", resourceType = "project")
public Map<String, Long> moduleCount(@Validated @RequestBody ApiModuleProviderRequest request) {
public Map<String, Long> moduleCount(@Validated @RequestBody AssociateCaseModuleProviderRequest request) {
return functionalTestCaseService.moduleCount(request, false);
}
@PostMapping("/associate/api/module/tree")
@Operation(summary = "接口测试-接口管理-模块-查找模块")
@PostMapping("/associate/case/module/tree")
@Operation(summary = "用例管理-功能用例-关联其他用例-查找模块")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
@CheckOwner(resourceId = "#request.projectId", resourceType = "project")
public List<BaseTreeNode> getTree(@RequestBody @Validated CaseApiModuleRequest request) {
public List<BaseTreeNode> getTree(@RequestBody @Validated AssociateCaseModuleRequest request) {
return functionalTestCaseService.getTree(request);
}
@ -76,13 +78,20 @@ public class FunctionalTestCaseController {
@Operation(summary = "用例管理-功能用例-关联其他用例-取消关联用例")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
@CheckOwner(resourceId = "#request.projectId", resourceType = "project")
public void disassociateCase(@Validated @RequestBody FunctionalTestCaseDisassociateRequest request) {
public void disassociateCase(@Validated @RequestBody DisassociateOtherCaseRequest request) {
functionalTestCaseService.disassociateCase(request);
}
@PostMapping("/has/associate/case/page")
@Operation(summary = "用例管理-功能用例-关联其他用例-获取已关联的用例列表")
@RequiresPermissions(value = {PermissionConstants.FUNCTIONAL_CASE_READ_ADD, PermissionConstants.FUNCTIONAL_CASE_READ_UPDATE, PermissionConstants.FUNCTIONAL_CASE_READ_DELETE}, logical = Logical.OR)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public Pager<List<FunctionalCaseTestDTO>> getAssociateOtherCaseList(@Validated @RequestBody FunctionalCaseTestRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "create_time desc");
return PageUtils.setPageInfo(page, functionalTestCaseService.hasAssociatePage(request));
}

View File

@ -0,0 +1,21 @@
package io.metersphere.functional.dto;
import io.metersphere.functional.domain.FunctionalCaseTest;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class FunctionalCaseTestDTO extends FunctionalCaseTest {
@Schema(description = "用例所属项目名称")
private String projectName;
@Schema(description = "用例所在版本名称")
private String versionName;
@Schema(description = "用例名称")
private String sourceName;
@Schema(description = "用例Id")
private String sourceNum;
}

View File

@ -1,6 +1,6 @@
package io.metersphere.functional.mapper;
import io.metersphere.functional.request.CaseApiModuleRequest;
import io.metersphere.functional.request.AssociateCaseModuleRequest;
import io.metersphere.project.dto.NodeSortQueryParam;
import io.metersphere.system.dto.sdk.BaseModule;
import io.metersphere.system.dto.sdk.BaseTreeNode;
@ -25,7 +25,7 @@ public interface ExtFunctionalCaseModuleMapper {
List<BaseTreeNode> selectIdAndParentIdByProjectId(String projectId);
List<BaseTreeNode> selectApiCaseModuleByRequest(@Param("request") CaseApiModuleRequest request);
List<BaseTreeNode> selectApiCaseModuleByRequest(@Param("request") AssociateCaseModuleRequest request);
}

View File

@ -1,13 +1,15 @@
package io.metersphere.functional.mapper;
import io.metersphere.functional.request.FunctionalTestCaseDisassociateRequest;
import io.metersphere.functional.dto.FunctionalCaseTestDTO;
import io.metersphere.functional.request.DisassociateOtherCaseRequest;
import io.metersphere.functional.request.FunctionalCaseTestRequest;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtFunctionalCaseTestMapper {
List<String> getIds(@Param("request") FunctionalTestCaseDisassociateRequest request);
List<String> getIds(@Param("request") DisassociateOtherCaseRequest request);
List<FunctionalCaseTestDTO> getList(@Param("request") FunctionalCaseTestRequest request);
}

View File

@ -21,6 +21,41 @@
1 = 1
</select>
<select id="getList" parameterType="io.metersphere.functional.request.FunctionalCaseTestRequest" resultType="io.metersphere.functional.dto.FunctionalCaseTestDTO">
SELECT
fct.id,
fct.case_id,
fct.source_id,
fct.source_type,
fct.project_id,
fct.version_id,
fct.create_time,
p.name as projectName,
v.name as versionName,
NULLIF(atc.name, scenario.name) as sourceName,
NULLIF(atc.num, scenario.num) as sourceNum
FROM
functional_case_test fct
LEFT JOIN project p ON fct.project_id = p.id
LEFT JOIN project_version v ON fct.version_id = v.id
LEFT JOIN api_test_case atc ON fct.source_id = atc.id
LEFT JOIN api_scenario scenario ON fct.source_id = scenario.id
WHERE fct.case_id = #{request.sourceId}
<if test="request.sourceType != null and request.sourceType != ''">
AND fct.source_type = #{request.sourceType}
</if>
<if test="request.projectId != null and request.projectId != ''">
AND fct.project_id = #{request.projectId}
</if>
<if test="request.keyword != null and request.keyword != ''">
and (
atc.name like concat('%', #{request.keyword},'%')
or scenario.name like concat('%', #{request.keyword},'%')
)
</if>
order by fct.create_time desc
</select>
<sql id="queryWhereConditionByBaseQueryRequest">
<if test="request.condition.keyword != null and request.sourceType == 'API'">
functional_case_test.source_id not in

View File

@ -10,7 +10,7 @@ import lombok.Data;
import java.util.List;
@Data
public class CaseApiModuleRequest extends BaseCondition {
public class AssociateCaseModuleRequest extends BaseCondition {
@Schema(description = "模块ID(根据模块树查询时要把当前节点以及子节点都放在这里。)")
private List<@NotBlank String> moduleIds;

View File

@ -6,7 +6,7 @@ import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class FunctionalTestCaseDisassociateRequest extends BaseFunctionalCaseBatchDTO {
public class DisassociateOtherCaseRequest extends BaseFunctionalCaseBatchDTO {
@Schema(description = "功能用例选择的项目id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{functional_test_case_disassociate_request.case_id.not_blank}")

View File

@ -0,0 +1,23 @@
package io.metersphere.functional.request;
import io.metersphere.system.dto.sdk.BasePageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Data
public class FunctionalCaseTestRequest extends BasePageRequest {
@Schema(description = "关联关系表里主ID eg:功能用例关联接口用例时为功能用例id")
@NotBlank(message = "{api_definition.project_id.not_blank}")
@Size(min = 1, max = 50, message = "{api_definition.project_id.length_range}")
private String sourceId;
@Schema(description = "项目ID")
private String projectId;
@Schema(description = "关联用例的类型(API,SCENARIO,UI,PERFORMANCE)")
private String sourceType;
}

View File

@ -1,16 +1,19 @@
package io.metersphere.functional.service;
import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.functional.constants.AssociateCaseType;
import io.metersphere.functional.domain.FunctionalCaseTest;
import io.metersphere.functional.domain.FunctionalCaseTestExample;
import io.metersphere.functional.dto.FunctionalCaseTestDTO;
import io.metersphere.functional.mapper.ExtFunctionalCaseModuleMapper;
import io.metersphere.functional.mapper.ExtFunctionalCaseTestMapper;
import io.metersphere.functional.mapper.FunctionalCaseTestMapper;
import io.metersphere.functional.request.CaseApiModuleRequest;
import io.metersphere.functional.request.FunctionalTestCaseDisassociateRequest;
import io.metersphere.functional.request.AssociateCaseModuleRequest;
import io.metersphere.functional.request.DisassociateOtherCaseRequest;
import io.metersphere.functional.request.FunctionalCaseTestRequest;
import io.metersphere.provider.BaseAssociateApiProvider;
import io.metersphere.request.ApiModuleProviderRequest;
import io.metersphere.request.AssociateCaseModuleProviderRequest;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.sdk.util.LogUtils;
@ -75,7 +78,7 @@ public class FunctionalTestCaseService {
* @param deleted 接口定义是否删除
* @return 接口模块统计数量
*/
public Map<String, Long> moduleCount(ApiModuleProviderRequest request, boolean deleted) {
public Map<String, Long> moduleCount(AssociateCaseModuleProviderRequest request, boolean deleted) {
return provider.moduleCount("functional_case_test", "case_id", "source_id", request, deleted);
}
@ -102,17 +105,18 @@ public class FunctionalTestCaseService {
}
private void associateApi(AssociateOtherCaseRequest request, boolean deleted, String userId) {
List<String> selectIds = provider.getSelectIds(request, deleted);
if (CollectionUtils.isEmpty(selectIds)) {
List<ApiTestCase> apiTestCases = provider.getSelectApiTestCases(request, deleted);
if (CollectionUtils.isEmpty(apiTestCases)) {
return;
}
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
FunctionalCaseTestMapper caseTestMapper = sqlSession.getMapper(FunctionalCaseTestMapper.class);
for (String selectId : selectIds) {
for (ApiTestCase apiTestCase : apiTestCases) {
FunctionalCaseTest functionalCaseTest = new FunctionalCaseTest();
functionalCaseTest.setCaseId(request.getSourceId());
functionalCaseTest.setProjectId(request.getProjectId());
functionalCaseTest.setSourceId(selectId);
functionalCaseTest.setSourceId(apiTestCase.getId());
functionalCaseTest.setVersionId(apiTestCase.getVersionId());
functionalCaseTest.setSourceType(request.getSourceType());
functionalCaseTest.setId(IdGenerator.random().generateId());
functionalCaseTest.setCreateUser(userId);
@ -130,7 +134,7 @@ public class FunctionalTestCaseService {
*
* @param request request
*/
public void disassociateCase(FunctionalTestCaseDisassociateRequest request) {
public void disassociateCase(DisassociateOtherCaseRequest request) {
List<String> functionalTestCaseIds = doSelectIds(request);
FunctionalCaseTestExample functionalCaseTestExample = new FunctionalCaseTestExample();
if (CollectionUtils.isNotEmpty(functionalTestCaseIds)) {
@ -140,7 +144,7 @@ public class FunctionalTestCaseService {
}
public List<String> doSelectIds(FunctionalTestCaseDisassociateRequest request) {
public List<String> doSelectIds(DisassociateOtherCaseRequest request) {
if (request.isSelectAll()) {
List<String> ids = extFunctionalCaseTestMapper.getIds(request);
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(request.getExcludeIds())) {
@ -152,8 +156,12 @@ public class FunctionalTestCaseService {
}
}
public List<BaseTreeNode> getTree(CaseApiModuleRequest request) {
public List<BaseTreeNode> getTree(AssociateCaseModuleRequest request) {
List<BaseTreeNode> fileModuleList = extFunctionalCaseModuleMapper.selectApiCaseModuleByRequest(request);
return functionalCaseModuleService.buildTreeAndCountResource(fileModuleList, true, Translator.get(UNPLANNED_API));
}
public List<FunctionalCaseTestDTO> hasAssociatePage(FunctionalCaseTestRequest request) {
return extFunctionalCaseTestMapper.getList(request);
}
}

View File

@ -1,21 +1,25 @@
package io.metersphere.functional.controller;
import io.metersphere.api.domain.ApiDefinitionModule;
import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.api.mapper.ApiDefinitionModuleMapper;
import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.functional.constants.AssociateCaseType;
import io.metersphere.functional.domain.FunctionalCaseTest;
import io.metersphere.functional.dto.FunctionalCaseTestDTO;
import io.metersphere.functional.mapper.FunctionalCaseTestMapper;
import io.metersphere.functional.request.CaseApiModuleRequest;
import io.metersphere.functional.request.FunctionalTestCaseDisassociateRequest;
import io.metersphere.functional.request.AssociateCaseModuleRequest;
import io.metersphere.functional.request.DisassociateOtherCaseRequest;
import io.metersphere.functional.request.FunctionalCaseTestRequest;
import io.metersphere.provider.BaseAssociateApiProvider;
import io.metersphere.request.ApiModuleProviderRequest;
import io.metersphere.request.AssociateCaseModuleProviderRequest;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.*;
import org.mockito.Mockito;
@ -34,15 +38,18 @@ import java.util.List;
public class FunctionalTestCaseControllerTests extends BaseTest {
private static final String URL_CASE_PAGE = "/functional/case/test/associate/api/page";
private static final String URL_CASE_PAGE = "/functional/case/test/associate/case/page";
private static final String URL_CASE_PAGE_MODULE_COUNT = "/functional/case/test/associate/api/module/count";
private static final String URL_CASE_PAGE_MODULE_COUNT = "/functional/case/test/associate/case/module/count";
private static final String URL_CASE_PAGE_ASSOCIATE = "/functional/case/test/associate/case";
private static final String URL_CASE_PAGE_DISASSOCIATE = "/functional/case/test/disassociate/case";
private static final String URL_CASE_MODULE_TREE = "/functional/case/test/associate/api/module/tree";
private static final String URL_CASE_MODULE_TREE = "/functional/case/test/associate/case/module/tree";
private static final String URL_HAS_CASE_PAGE = "/functional/case/test/has/associate/case/page";
@ -105,7 +112,7 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
@Test
@Order(3)
public void getModuleCountSuccess() throws Exception {
ApiModuleProviderRequest request = new ApiModuleProviderRequest();
AssociateCaseModuleProviderRequest request = new AssociateCaseModuleProviderRequest();
request.setSourceId("gyq_associate_case_id_1");
request.setProjectId("project_gyq_associate_test");
request.setKeyword("测试查询模块用");
@ -128,13 +135,16 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Assertions.assertNotNull(resultHolder);
List<String>operations = new ArrayList<>();
operations.add("gyq_associate_case_id_1");
Mockito.when(provider.getSelectIds(request, false)).thenReturn(operations);
List<ApiTestCase>operations = new ArrayList<>();
ApiTestCase apiTestCase = new ApiTestCase();
apiTestCase.setId("gyq_associate_case_id_1");
apiTestCase.setVersionId("11");
operations.add(apiTestCase);
Mockito.when(provider.getSelectApiTestCases(request, false)).thenReturn(operations);
Assertions.assertNotNull(resultHolder);
request.setSelectAll(false);
request.setProjectId("project-associate-case-test");
request.setSelectIds(operations);
request.setSelectIds(List.of("gyq_associate_case_id_1"));
mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_ASSOCIATE, request);
returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
@ -157,7 +167,7 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
@Order(5)
public void disassociateCaseSuccess() throws Exception {
addFunctionalCaseTest();
FunctionalTestCaseDisassociateRequest request = new FunctionalTestCaseDisassociateRequest();
DisassociateOtherCaseRequest request = new DisassociateOtherCaseRequest();
request.setSourceType(AssociateCaseType.API);
request.setCaseId("gyq_associate_functional_case_id_1");
request.setSelectAll(true);
@ -168,7 +178,7 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
Assertions.assertNotNull(resultHolder);
FunctionalCaseTest functionalCaseTest = functionalCaseTestMapper.selectByPrimaryKey("functionalCaseTestHasId");
Assertions.assertNull(functionalCaseTest);
request = new FunctionalTestCaseDisassociateRequest();
request = new DisassociateOtherCaseRequest();
request.setSourceType(AssociateCaseType.API);
request.setCaseId("gyq_associate_case_id_1");
request.setSelectAll(true);
@ -178,7 +188,7 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Assertions.assertNotNull(resultHolder);
request = new FunctionalTestCaseDisassociateRequest();
request = new DisassociateOtherCaseRequest();
request.setSourceType(AssociateCaseType.API);
request.setCaseId("gyq_associate_case_id_1");
request.setSelectAll(false);
@ -205,12 +215,28 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
apiDefinitionModuleMapper.insert(apiDefinitionModule);
List<BaseTreeNode> moduleTreeNode = this.getModuleTreeNode();
Assertions.assertNotNull(moduleTreeNode);
System.out.println(JSON.toJSONString(moduleTreeNode));
}
@Test
@Order(7)
public void getAssociateOtherCaseListSuccess() throws Exception {
addFunctionalCaseTest();
FunctionalCaseTestRequest request = new FunctionalCaseTestRequest();
request.setSourceType(AssociateCaseType.API);
request.setSourceId("gyq_associate_functional_case_id_1");
request.setCurrent(1);
request.setPageSize(10);
MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_HAS_CASE_PAGE, request);
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder sortHolder = JSON.parseObject(sortData, ResultHolder.class);
Pager<?> sortPageData = JSON.parseObject(JSON.toJSONString(sortHolder.getData()), Pager.class);
// 返回值中取出第一条ID最大的数据, 并判断是否是default-admin
List<FunctionalCaseTestDTO> functionalCaseTestDTOS = JSON.parseArray(JSON.toJSONString(sortPageData.getList()), FunctionalCaseTestDTO.class);
Assertions.assertNotNull(functionalCaseTestDTOS);
}
private List<BaseTreeNode> getModuleTreeNode() throws Exception {
MvcResult result = this.requestPostWithOkAndReturn(URL_CASE_MODULE_TREE, new CaseApiModuleRequest() {{
MvcResult result = this.requestPostWithOkAndReturn(URL_CASE_MODULE_TREE, new AssociateCaseModuleRequest() {{
this.setProtocol("HTTP");
this.setProjectId("project-associate-case-test");
this.setSourceType(AssociateCaseType.API);
@ -224,6 +250,7 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
FunctionalCaseTest functionalCaseTest = new FunctionalCaseTest();
functionalCaseTest.setId("functionalCaseTestHasId");
functionalCaseTest.setCaseId("gyq_associate_functional_case_id_1");
functionalCaseTest.setVersionId("1.0");
functionalCaseTest.setSourceId("gyq_api_case_id_1");
functionalCaseTest.setSourceType(AssociateCaseType.API);
functionalCaseTest.setProjectId("gyq-organization-associate-case-test");
@ -234,5 +261,4 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
functionalCaseTestMapper.insert(functionalCaseTest);
}
}