feat(测试计划): 关联抽屉接口场景列表

This commit is contained in:
WangXu10 2024-06-07 14:04:19 +08:00 committed by 刘瑞斌
parent 3aac154c77
commit 722823d1a6
16 changed files with 129 additions and 19 deletions

View File

@ -162,7 +162,7 @@ public class ApiTestCaseController {
public Pager<List<ApiTestCaseDTO>> page(@Validated @RequestBody ApiTestCasePageRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString("id")) ? request.getSortString("id") : "pos desc, id desc");
return PageUtils.setPageInfo(page, apiTestCaseService.page(request, false, true));
return PageUtils.setPageInfo(page, apiTestCaseService.page(request, false, true,null));
}
@PostMapping("/batch/delete")
@ -204,7 +204,7 @@ public class ApiTestCaseController {
public Pager<List<ApiTestCaseDTO>> pageTrash(@Validated @RequestBody ApiTestCasePageRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString("id")) ? request.getSortString("id") : "delete_time desc, id desc");
return PageUtils.setPageInfo(page, apiTestCaseService.page(request, true, true));
return PageUtils.setPageInfo(page, apiTestCaseService.page(request, true, true, null));
}
@PostMapping("/edit/pos")

View File

@ -65,7 +65,7 @@ public class ApiScenarioController {
public Pager<List<ApiScenarioDTO>> getPage(@Validated @RequestBody ApiScenarioPageRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString("id")) ? request.getSortString("id") : "pos desc, id desc");
return PageUtils.setPageInfo(page, apiScenarioService.getScenarioPage(request));
return PageUtils.setPageInfo(page, apiScenarioService.getScenarioPage(request, true, null));
}
@PostMapping("/trash/page")
@ -76,7 +76,7 @@ public class ApiScenarioController {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString("id")) ? request.getSortString("id") : "delete_time desc, id desc");
request.setDeleted(true);
return PageUtils.setPageInfo(page, apiScenarioService.getScenarioPage(request));
return PageUtils.setPageInfo(page, apiScenarioService.getScenarioPage(request, true, null));
}
@GetMapping("follow/{id}")

View File

@ -33,4 +33,7 @@ public class ApiScenarioModuleRequest extends BaseCondition {
@Schema(description = "版本引用fk")
@Size(max = 50, message = "{api_definition.ref_id.length_range}")
private String refId;
@Schema(description = "测试计划id")
private String testPlanId;
}

View File

@ -16,7 +16,7 @@ import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtApiScenarioMapper {
List<ApiScenarioDTO> list(@Param("request") ApiScenarioPageRequest request);
List<ApiScenarioDTO> list(@Param("request") ApiScenarioPageRequest request, @Param("isRepeat") boolean isRepeat, @Param("testPlanId") String testPlanId);
List<String> getIds(@Param("request") ApiScenarioBatchRequest request, @Param("deleted") boolean deleted);
@ -62,6 +62,7 @@ public interface ExtApiScenarioMapper {
/**
* 获取缺陷未关联的场景用例列表
*
* @param request provider参数
* @param deleted 是否删除状态
* @param sort 排序
@ -71,9 +72,10 @@ public interface ExtApiScenarioMapper {
/**
* 根据关联条件获取关联的用例ID
*
* @param request 关联参数
* @param deleted 是否删除状态
* @return 关联的用例ID集合
*/
List<String> getSelectIdsByAssociateParam(@Param("request")AssociateOtherCaseRequest request, @Param("deleted") boolean deleted);
List<String> getSelectIdsByAssociateParam(@Param("request") AssociateOtherCaseRequest request, @Param("deleted") boolean deleted);
}

View File

@ -40,7 +40,11 @@
#{excludeId}
</foreach>
</if>
<if test="!isRepeat and testPlanId != null">
AND api_scenario.id not in (
select test_plan_api_scenario.api_scenario_id from test_plan_api_scenario where test_plan_api_scenario.test_plan_id = #{testPlanId}
)
</if>
</select>
<select id="getIds" resultType="java.lang.String">
@ -553,6 +557,11 @@
FROM api_scenario
where api_scenario.deleted =#{deleted}
<include refid="queryWhereCondition"/>
<if test="request.testPlanId != null and request.testPlanId != ''">
AND api_scenario.id not in (
select test_plan_api_scenario.api_scenario_id from test_plan_api_scenario where test_plan_api_scenario.test_plan_id = #{request.testPlanId}
)
</if>
GROUP BY api_scenario.module_id
</select>

View File

@ -26,7 +26,7 @@ public interface ExtApiTestCaseMapper {
Long getPos(@Param("projectId") String projectId);
List<ApiTestCaseDTO> listByRequest(@Param("request") ApiTestCasePageRequest request, @Param("deleted") boolean deleted, @Param("isRepeat") boolean isRepeat);
List<ApiTestCaseDTO> listByRequest(@Param("request") ApiTestCasePageRequest request, @Param("deleted") boolean deleted, @Param("isRepeat") boolean isRepeat, @Param("testPlanId") String testPlanId);
List<String> getIds(@Param("request") ApiTestCaseBatchRequest request, @Param("deleted") boolean deleted);

View File

@ -66,9 +66,9 @@
INNER JOIN api_definition a ON atc.api_definition_id = a.id
WHERE atc.deleted =#{deleted}
<include refid="queryWhereCondition"/>
<if test="!isRepeat">
<if test="!isRepeat and testPlanId != null">
AND atc.id not in (
select test_plan_api_case.api_case_id from test_plan_api_case where test_plan_api_case.test_plan_id = #{request.testPlanId}
select test_plan_api_case.api_case_id from test_plan_api_case where test_plan_api_case.test_plan_id = #{testPlanId}
)
</if>
</select>

View File

@ -315,11 +315,11 @@ public class ApiTestCaseService extends MoveNodeService {
apiTestCaseMapper.updateByPrimaryKeySelective(update);
}
public List<ApiTestCaseDTO> page(ApiTestCasePageRequest request, boolean deleted, boolean isRepeat) {
public List<ApiTestCaseDTO> page(ApiTestCasePageRequest request, boolean deleted, boolean isRepeat, String testPlanId) {
if (CollectionUtils.isEmpty(request.getProtocols())) {
return new ArrayList<>();
}
List<ApiTestCaseDTO> apiCaseLists = extApiTestCaseMapper.listByRequest(request, deleted, isRepeat);
List<ApiTestCaseDTO> apiCaseLists = extApiTestCaseMapper.listByRequest(request, deleted, isRepeat, testPlanId);
buildApiTestCaseDTO(apiCaseLists);
return apiCaseLists;
}

View File

@ -12,6 +12,8 @@ import io.metersphere.api.mapper.ApiScenarioMapper;
import io.metersphere.api.mapper.ApiScenarioModuleMapper;
import io.metersphere.api.mapper.ExtApiScenarioMapper;
import io.metersphere.api.mapper.ExtApiScenarioModuleMapper;
import io.metersphere.plan.domain.TestPlanConfig;
import io.metersphere.plan.mapper.TestPlanConfigMapper;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.NodeSortDTO;
import io.metersphere.project.service.ModuleTreeService;
@ -23,6 +25,7 @@ import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
@ -53,6 +56,8 @@ public class ApiScenarioModuleService extends ModuleTreeService {
private ApiScenarioMapper apiScenarioMapper;
@Resource
private ExtApiScenarioMapper extApiScenarioMapper;
@Resource
private TestPlanConfigMapper testPlanConfigMapper;
public List<BaseTreeNode> getTree(ApiScenarioModuleRequest request) {
//接口的树结构是 模块子模块+接口 接口为非delete状态的
@ -245,6 +250,9 @@ public class ApiScenarioModuleService extends ModuleTreeService {
}
public Map<String, Long> moduleCount(ApiScenarioModuleRequest request, boolean deleted) {
if (StringUtils.isNotEmpty(request.getTestPlanId())) {
this.checkTestPlanRepeatCase(request);
}
request.setModuleIds(null);
//查找根据moduleIds查找模块下的接口数量 查非delete状态的
List<ModuleCountDTO> moduleCountDTOList = extApiScenarioMapper.countModuleIdByRequest(request, deleted);
@ -256,6 +264,14 @@ public class ApiScenarioModuleService extends ModuleTreeService {
return moduleCountMap;
}
private void checkTestPlanRepeatCase(ApiScenarioModuleRequest request) {
TestPlanConfig testPlanConfig = testPlanConfigMapper.selectByPrimaryKey(request.getTestPlanId());
if (testPlanConfig != null && BooleanUtils.isTrue(testPlanConfig.getRepeatCase())) {
//测试计划允许重复用例意思就是统计不受测试计划影响去掉这个条件
request.setTestPlanId(null);
}
}
public List<BaseTreeNode> getTrashTree(ApiScenarioModuleRequest request) {
ApiScenarioExample example = new ApiScenarioExample();
example.createCriteria().andProjectIdEqualTo(request.getProjectId()).andDeletedEqualTo(true);

View File

@ -174,10 +174,10 @@ public class ApiScenarioService extends MoveNodeService {
private static final String SCENARIO = "SCENARIO";
public List<ApiScenarioDTO> getScenarioPage(ApiScenarioPageRequest request) {
public List<ApiScenarioDTO> getScenarioPage(ApiScenarioPageRequest request, boolean isRepeat, String testPlanId) {
//CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(request, userId);
//TODO 场景的自定义字段 等设计 不一定会有
List<ApiScenarioDTO> list = extApiScenarioMapper.list(request);
List<ApiScenarioDTO> list = extApiScenarioMapper.list(request, isRepeat, testPlanId);
if (CollectionUtils.isNotEmpty(list)) {
processApiScenario(list);
}

View File

@ -96,7 +96,7 @@ public class TestPlanApiCaseController {
@PostMapping("/batch/update/executor")
@Operation(summary = "测试计划-计划详情-功能用例-批量更新执行人")
@Operation(summary = "测试计划-计划详情-接口用例列表-批量更新执行人")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_UPDATE)
@CheckOwner(resourceId = "#request.getTestPlanId()", resourceType = "test_plan")
@Log(type = OperationLogType.UPDATE, expression = "#msClass.batchUpdateExecutor(#request)", msClass = TestPlanApiCaseLogService.class)
@ -105,5 +105,5 @@ public class TestPlanApiCaseController {
}
//TODO 计划集 type
//TODO 批量移动 计划集内
}

View File

@ -4,12 +4,15 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.definition.ApiDefinitionDTO;
import io.metersphere.api.dto.definition.ApiTestCaseDTO;
import io.metersphere.api.dto.scenario.ApiScenarioDTO;
import io.metersphere.functional.dto.FunctionalCasePageDTO;
import io.metersphere.functional.request.FunctionalCasePageRequest;
import io.metersphere.functional.service.FunctionalCaseService;
import io.metersphere.plan.dto.request.TestPlanApiCaseRequest;
import io.metersphere.plan.dto.request.TestPlanApiRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioRequest;
import io.metersphere.plan.service.TestPlanApiCaseService;
import io.metersphere.plan.service.TestPlanApiScenarioService;
import io.metersphere.plan.service.TestPlanConfigService;
import io.metersphere.plan.service.TestPlanManagementService;
import io.metersphere.sdk.constants.PermissionConstants;
@ -42,6 +45,8 @@ public class TestPlanAssociateController {
private TestPlanApiCaseService testPlanApiCaseService;
@Resource
private TestPlanManagementService testPlanManagementService;
@Resource
private TestPlanApiScenarioService testPlanApiScenarioService;
@PostMapping("/page")
@Operation(summary = "测试计划-关联用例弹窗-功能用例列表查询(项目)")
@ -92,4 +97,20 @@ public class TestPlanAssociateController {
return PageUtils.setPageInfo(page, testPlanApiCaseService.getApiCasePage(request, isRepeat));
}
@PostMapping("/api/scenario/page")
@Operation(summary = "测试计划-关联用例弹窗-接口场景列表查询(项目)")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
@CheckOwner(resourceId = "#request.getTestPlanId()", resourceType = "test_plan")
public Pager<List<ApiScenarioDTO>> getApiScenarioPage(@Validated @RequestBody TestPlanApiScenarioRequest request) {
boolean moduleIsOpen = testPlanManagementService.checkModuleIsOpenByProjectId(request.getProjectId());
if (!moduleIsOpen) {
return new Pager<>();
}
boolean isRepeat = testPlanConfigService.isRepeatCase(request.getTestPlanId());
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "pos desc");
return PageUtils.setPageInfo(page, testPlanApiScenarioService.getApiScenarioPage(request, isRepeat));
}
}

View File

@ -0,0 +1,18 @@
package io.metersphere.plan.dto.request;
import io.metersphere.api.dto.scenario.ApiScenarioPageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* @author wx
*/
@Data
public class TestPlanApiScenarioRequest extends ApiScenarioPageRequest {
@Schema(description = "测试计划id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.id.not_blank}")
private String testPlanId;
}

View File

@ -181,7 +181,7 @@ public class TestPlanApiCaseService extends TestPlanResourceService {
if (CollectionUtils.isEmpty(request.getProtocols())) {
return new ArrayList<>();
}
return apiTestCaseService.page(request, isRepeat, false);
return apiTestCaseService.page(request, isRepeat, false, request.getTestPlanId());
}

View File

@ -1,11 +1,14 @@
package io.metersphere.plan.service;
import io.metersphere.api.dto.scenario.ApiScenarioDTO;
import io.metersphere.api.service.scenario.ApiScenarioService;
import io.metersphere.plan.constants.AssociateCaseType;
import io.metersphere.plan.domain.TestPlanApiScenario;
import io.metersphere.plan.domain.TestPlanApiScenarioExample;
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
import io.metersphere.plan.dto.TestPlanCollectionDTO;
import io.metersphere.plan.dto.request.BaseCollectionAssociateRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioRequest;
import io.metersphere.plan.mapper.ExtTestPlanApiScenarioMapper;
import io.metersphere.plan.mapper.TestPlanApiScenarioMapper;
import io.metersphere.plan.mapper.TestPlanCollectionMapper;
@ -38,6 +41,8 @@ public class TestPlanApiScenarioService extends TestPlanResourceService {
private ExtTestPlanApiScenarioMapper extTestPlanApiScenarioMapper;
@Resource
private TestPlanCollectionMapper testPlanCollectionMapper;
@Resource
private ApiScenarioService apiScenarioService;
@Override
public void deleteBatchByTestPlanId(List<String> testPlanIdList) {
@ -101,7 +106,7 @@ public class TestPlanApiScenarioService extends TestPlanResourceService {
}
@Override
public void associateCollection(String planId, Map<String, List<BaseCollectionAssociateRequest>> collectionAssociates,String userId) {
public void associateCollection(String planId, Map<String, List<BaseCollectionAssociateRequest>> collectionAssociates, String userId) {
List<BaseCollectionAssociateRequest> apiScenarios = collectionAssociates.get(AssociateCaseType.API_SCENARIO);
// TODO: 调用具体的关联场景用例入库方法 入参{计划ID, 测试集ID, 关联的用例ID集合}
}
@ -118,4 +123,17 @@ public class TestPlanApiScenarioService extends TestPlanResourceService {
scenarioCaseExample.createCriteria().andTestPlanIdEqualTo(planId);
scenarioBatchMapper.updateByExampleSelective(record, scenarioCaseExample);
}
/**
* 未关联接口场景列表
*
* @param request
* @param isRepeat
* @return
*/
public List<ApiScenarioDTO> getApiScenarioPage(TestPlanApiScenarioRequest request, boolean isRepeat) {
List<ApiScenarioDTO> scenarioPage = apiScenarioService.getScenarioPage(request, isRepeat, request.getTestPlanId());
return scenarioPage;
}
}

View File

@ -3,6 +3,7 @@ package io.metersphere.plan.controller;
import io.metersphere.functional.request.FunctionalCasePageRequest;
import io.metersphere.plan.dto.request.TestPlanApiCaseRequest;
import io.metersphere.plan.dto.request.TestPlanApiRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioRequest;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
@ -24,6 +25,7 @@ public class TestPlanAssociateControllerTests extends BaseTest {
public static final String FUNCTIONAL_CASE_ASSOCIATION_URL = "/test-plan/association/page";
public static final String API_ASSOCIATION_URL = "/test-plan/association/api/page";
public static final String API_CASE_ASSOCIATION_URL = "/test-plan/association/api/case/page";
public static final String API_SCENARIO_URL = "/test-plan/association/api/scenario/page";
@Test
@Order(1)
@ -91,4 +93,25 @@ public class TestPlanAssociateControllerTests extends BaseTest {
Assertions.assertNotNull(resultHolder);
}
@Test
@Order(4)
public void testApiScenarioPageList() throws Exception {
TestPlanApiScenarioRequest request = new TestPlanApiScenarioRequest();
request.setCurrent(1);
request.setPageSize(10);
request.setTestPlanId("wxx_1");
request.setProjectId("1234567");
this.requestPost(API_SCENARIO_URL, request);
request.setProjectId("wx_1234");
this.requestPost(API_SCENARIO_URL, request);
request.setSort(new HashMap<>() {{
put("createTime", "desc");
}});
MvcResult mvcResult = this.requestPostWithOkAndReturn(API_SCENARIO_URL, request);
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Assertions.assertNotNull(resultHolder);
}
}