feat(测试计划): 新增测试计划功能用例获取详情表的接口

This commit is contained in:
guoyuqi 2024-05-16 16:44:57 +08:00 committed by Craftsman
parent 37deac293a
commit 29de7455a3
5 changed files with 160 additions and 12 deletions

View File

@ -6,7 +6,6 @@ import io.metersphere.functional.dto.FunctionalCaseStepDTO;
import io.metersphere.functional.dto.FunctionalMinderTreeDTO;
import io.metersphere.functional.dto.MinderOptionDTO;
import io.metersphere.functional.mapper.FunctionalCaseBlobMapper;
import io.metersphere.functional.mapper.FunctionalCaseCustomFieldMapper;
import io.metersphere.functional.mapper.FunctionalCaseMapper;
import io.metersphere.functional.mapper.FunctionalCaseModuleMapper;
import io.metersphere.functional.request.*;
@ -48,8 +47,6 @@ public class FunctionalCaseMinderControllerTest extends BaseTest {
private FunctionalCaseMapper functionalCaseMapper;
@Resource
private FunctionalCaseModuleMapper functionalCaseModuleMapper;
@Resource
private FunctionalCaseCustomFieldMapper functionalCaseCustomFieldMapper;
@Test
@Order(1)

View File

@ -3,6 +3,7 @@ package io.metersphere.plan.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.dto.BugProviderDTO;
import io.metersphere.functional.dto.FunctionalCaseDetailDTO;
import io.metersphere.plan.constants.TestPlanResourceConfig;
import io.metersphere.plan.dto.request.*;
import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
@ -47,7 +48,7 @@ public class TestPlanFunctionalCaseController {
@PostMapping(value = "/sort")
@Operation(summary = "测试计划功能用例-关联功能用例")
@Operation(summary = "测试计划功能用例-功能用例拖拽排序")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_UPDATE)
@CheckOwner(resourceId = "#request.getTestPlanId()", resourceType = "test_plan")
public TestPlanResourceSortResponse sortNode(@Validated @RequestBody ResourceSortRequest request) {
@ -161,6 +162,14 @@ public class TestPlanFunctionalCaseController {
testPlanFunctionalCaseService.batchUpdateExecutor(request);
}
@GetMapping("/detail/{id}")
@Operation(summary = "测试计划-计划详情-功能用例-获取用例详情")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
public FunctionalCaseDetailDTO getFunctionalCaseDetail(@PathVariable String id) {
String userId = SessionUtils.getUserId();
return testPlanFunctionalCaseService.getFunctionalCaseDetail(id, userId);
}
@PostMapping("/exec/history")
@Operation(summary = "测试计划-计划详情-功能用例-执行历史")

View File

@ -13,6 +13,7 @@ import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.functional.domain.FunctionalCaseBlob;
import io.metersphere.functional.domain.FunctionalCaseExample;
import io.metersphere.functional.domain.FunctionalCaseModule;
import io.metersphere.functional.dto.*;
import io.metersphere.functional.dto.FunctionalCaseCustomFieldDTO;
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
import io.metersphere.functional.dto.FunctionalCaseModuleDTO;
@ -22,10 +23,7 @@ import io.metersphere.functional.mapper.FunctionalCaseMapper;
import io.metersphere.functional.service.FunctionalCaseAttachmentService;
import io.metersphere.functional.service.FunctionalCaseModuleService;
import io.metersphere.functional.service.FunctionalCaseService;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanCaseExecuteHistory;
import io.metersphere.plan.domain.TestPlanFunctionalCase;
import io.metersphere.plan.domain.TestPlanFunctionalCaseExample;
import io.metersphere.plan.domain.*;
import io.metersphere.plan.dto.AssociationNodeSortDTO;
import io.metersphere.plan.dto.ResourceLogInsertModule;
import io.metersphere.plan.dto.TestPlanResourceAssociationParam;
@ -57,6 +55,7 @@ import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.log.dto.LogDTO;
import io.metersphere.system.log.service.OperationLogService;
import io.metersphere.system.mapper.ExtCheckOwnerMapper;
import io.metersphere.system.notice.constants.NoticeConstants;
import io.metersphere.system.service.UserLoginService;
import io.metersphere.system.uid.IDGenerator;
@ -120,10 +119,17 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
private FunctionalCaseMapper functionalCaseMapper;
@Resource
private OperationLogService operationLogService;
@Resource
private ExtCheckOwnerMapper extCheckOwnerMapper;
@Resource
private FunctionalCaseBlobMapper functionalCaseBlobMapper;
private static final String CASE_MODULE_COUNT_ALL = "all";
private static final String FUNCTIONAL_CASE = "functional_case";
private static final String CHECK_OWNER_CASE = "check_owner_case";
@Override
public int deleteBatchByTestPlanId(List<String> testPlanIdList) {
TestPlanFunctionalCaseExample example = new TestPlanFunctionalCaseExample();
@ -568,6 +574,58 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
return list;
}
public FunctionalCaseDetailDTO getFunctionalCaseDetail(String id, String userId) {
TestPlanFunctionalCase planFunctionalCase = testPlanFunctionalCaseMapper.selectByPrimaryKey(id);
String caseId = planFunctionalCase.getFunctionalCaseId();
if (!extCheckOwnerMapper.checkoutOwner(FUNCTIONAL_CASE, userId, List.of(caseId))) {
throw new MSException(Translator.get(CHECK_OWNER_CASE));
}
FunctionalCaseDetailDTO functionalCaseDetail = functionalCaseService.getFunctionalCaseDetail(caseId, userId);
String caseDetailSteps = functionalCaseDetail.getSteps();
TestPlanCaseExecuteHistoryExample testPlanCaseExecuteHistoryExample = new TestPlanCaseExecuteHistoryExample();
testPlanCaseExecuteHistoryExample.createCriteria().andCaseIdEqualTo(caseId).andTestPlanCaseIdEqualTo(id);
testPlanCaseExecuteHistoryExample.setOrderByClause("create_time DESC");
List<TestPlanCaseExecuteHistory> testPlanCaseExecuteHistories = testPlanCaseExecuteHistoryMapper.selectByExampleWithBLOBs(testPlanCaseExecuteHistoryExample);
List<FunctionalCaseStepDTO> functionalCaseStepDTOS = new ArrayList<>();
if (CollectionUtils.isNotEmpty(testPlanCaseExecuteHistories)) {
TestPlanCaseExecuteHistory testPlanCaseExecuteHistory = testPlanCaseExecuteHistories.get(0);
if (StringUtils.isNotBlank(caseDetailSteps)) {
List<FunctionalCaseStepDTO> newCaseSteps = JSON.parseArray(caseDetailSteps, FunctionalCaseStepDTO.class);
compareStep(testPlanCaseExecuteHistory, newCaseSteps);
functionalCaseStepDTOS = newCaseSteps;
functionalCaseDetail.setSteps(JSON.toJSONString(functionalCaseStepDTOS));
}
} else {
if (StringUtils.isNotBlank(caseDetailSteps)) {
functionalCaseStepDTOS = JSON.parseArray(caseDetailSteps, FunctionalCaseStepDTO.class);
}
functionalCaseDetail.setSteps(JSON.toJSONString(functionalCaseStepDTOS));
}
return functionalCaseDetail;
}
private static void compareStep(TestPlanCaseExecuteHistory testPlanCaseExecuteHistory, List<FunctionalCaseStepDTO> newCaseSteps) {
if (testPlanCaseExecuteHistory.getSteps() != null) {
String historyStepStr = new String(testPlanCaseExecuteHistory.getSteps(), StandardCharsets.UTF_8);
if (StringUtils.isNotBlank(historyStepStr)) {
List<FunctionalCaseStepDTO> historySteps = JSON.parseArray(historyStepStr, FunctionalCaseStepDTO.class);
newCaseSteps.forEach(newCaseStep->{
historySteps.forEach(historyStep->{
setHistoryInfo(newCaseStep, historyStep);
});
});
}
}
}
private static void setHistoryInfo(FunctionalCaseStepDTO newCaseStep, FunctionalCaseStepDTO historyStep) {
if (StringUtils.equals(historyStep.getDesc(), newCaseStep.getDesc()) && StringUtils.equals(historyStep.getResult(), newCaseStep.getResult())) {
newCaseStep.setExecuteResult(historyStep.getExecuteResult());
newCaseStep.setActualResult(historyStep.getActualResult());
}
}
public void editFunctionalCase(TestPlanCaseEditRequest request, String userId) {
TestPlanFunctionalCase planFunctionalCase = testPlanFunctionalCaseMapper.selectByPrimaryKey(request.getId());

View File

@ -4,9 +4,15 @@ import io.metersphere.bug.domain.BugRelationCase;
import io.metersphere.bug.domain.BugRelationCaseExample;
import io.metersphere.bug.mapper.BugRelationCaseMapper;
import io.metersphere.dto.BugProviderDTO;
import io.metersphere.functional.domain.FunctionalCaseBlob;
import io.metersphere.functional.dto.FunctionalCaseDetailDTO;
import io.metersphere.functional.dto.FunctionalCaseStepDTO;
import io.metersphere.functional.mapper.FunctionalCaseBlobMapper;
import io.metersphere.plan.domain.TestPlanCaseExecuteHistory;
import io.metersphere.plan.domain.TestPlanFunctionalCase;
import io.metersphere.plan.domain.TestPlanFunctionalCaseExample;
import io.metersphere.plan.dto.request.*;
import io.metersphere.plan.mapper.TestPlanCaseExecuteHistoryMapper;
import io.metersphere.plan.mapper.TestPlanFunctionalCaseMapper;
import io.metersphere.provider.BaseAssociateBugProvider;
import io.metersphere.request.AssociateBugPageRequest;
@ -15,6 +21,7 @@ import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.junit.jupiter.api.*;
import org.mockito.Mockito;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
@ -28,6 +35,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@AutoConfigureMockMvc
@ -43,14 +52,21 @@ public class TestPlanCaseControllerTests extends BaseTest {
public static final String FUNCTIONAL_CASE_RUN_URL = "/test-plan/functional/case/run";
public static final String FUNCTIONAL_CASE_BATCH_RUN_URL = "/test-plan/functional/case/batch/run";
public static final String FUNCTIONAL_CASE_BATCH_UPDATE_EXECUTOR_URL = "/test-plan/functional/case/batch/update/executor";
public static final String FUNCTIONAL_CASE_DETAIL = "/test-plan/functional/case/detail/";
public static final String FUNCTIONAL_CASE_EXEC_HISTORY_URL = "/test-plan/functional/case/exec/history";
public static final String FUNCTIONAL_CASE_EDIT_URL = "/test-plan/functional/case/edit";
@Resource
private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper;
@Resource
private TestPlanCaseExecuteHistoryMapper testPlanCaseExecuteHistoryMapper;
@Resource
BaseAssociateBugProvider baseAssociateBugProvider;
@Resource
BugRelationCaseMapper bugRelationCaseMapper;
@Resource
FunctionalCaseBlobMapper functionalCaseBlobMapper;
@Test
@ -251,4 +267,56 @@ public class TestPlanCaseControllerTests extends BaseTest {
request.setLastExecResult("SUCCESS");
this.requestPostWithOk(FUNCTIONAL_CASE_EDIT_URL, request);
}
@Test
@Order(16)
public void testGetDetail() throws Exception {
this.requestGet(FUNCTIONAL_CASE_DETAIL + "relate_case_1").andExpect(status().is5xxServerError());
MvcResult mvcResult = this.requestGetWithOkAndReturn(FUNCTIONAL_CASE_DETAIL + "gyq_disassociate_case_4");
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
FunctionalCaseDetailDTO functionalCaseDetailDTO = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), FunctionalCaseDetailDTO.class);
Assertions.assertTrue(CollectionUtils.isEmpty(JSON.parseArray(functionalCaseDetailDTO.getSteps(), FunctionalCaseDetailDTO.class)));
TestPlanCaseExecuteHistory testPlanCaseExecuteHistory = new TestPlanCaseExecuteHistory();
testPlanCaseExecuteHistory.setCaseId("gyq_disassociate_fc_4");
testPlanCaseExecuteHistory.setTestPlanCaseId("gyq_disassociate_case_4");
testPlanCaseExecuteHistory.setDeleted(false);
testPlanCaseExecuteHistory.setId("history_id");
testPlanCaseExecuteHistory.setCreateTime(System.currentTimeMillis());
testPlanCaseExecuteHistory.setCreateUser("admin");
testPlanCaseExecuteHistory.setStatus("SUCCESS");
testPlanCaseExecuteHistoryMapper.insertSelective(testPlanCaseExecuteHistory);
mvcResult = this.requestGetWithOkAndReturn(FUNCTIONAL_CASE_DETAIL + "gyq_disassociate_case_4");
returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Assertions.assertNotNull(resultHolder);
TestPlanCaseExecuteHistory testPlanCaseExecuteHistory1 = testPlanCaseExecuteHistoryMapper.selectByPrimaryKey("history_id");
FunctionalCaseStepDTO functionalCaseStepDTO = new FunctionalCaseStepDTO();
functionalCaseStepDTO.setId("id_step");
functionalCaseStepDTO.setNum(1);
functionalCaseStepDTO.setDesc("步骤一");
functionalCaseStepDTO.setResult("步骤一结果");
functionalCaseStepDTO.setActualResult("步骤一实际结果");
functionalCaseStepDTO.setExecuteResult("SUCCESS");
String jsonString = JSON.toJSONString(functionalCaseStepDTO);
testPlanCaseExecuteHistory1.setSteps(jsonString.getBytes());
testPlanCaseExecuteHistoryMapper.updateByPrimaryKeySelective(testPlanCaseExecuteHistory1);
FunctionalCaseBlob functionalCaseBlob = new FunctionalCaseBlob();
functionalCaseBlob.setId("gyq_disassociate_fc_4");
functionalCaseBlob.setSteps(jsonString.getBytes());
String textDescription = "textDescription";
String expectedResult = "expectedResult";
String prerequisite = "prerequisite";
String description = "description";
functionalCaseBlob.setPrerequisite(prerequisite.getBytes(StandardCharsets.UTF_8));
functionalCaseBlob.setTextDescription(textDescription.getBytes(StandardCharsets.UTF_8));
functionalCaseBlob.setExpectedResult(expectedResult.getBytes(StandardCharsets.UTF_8));
functionalCaseBlob.setDescription(description.getBytes(StandardCharsets.UTF_8));
functionalCaseBlobMapper.updateByPrimaryKeyWithBLOBs(functionalCaseBlob);
mvcResult = this.requestGetWithOkAndReturn(FUNCTIONAL_CASE_DETAIL + "gyq_disassociate_case_4");
returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(returnData, ResultHolder.class);
functionalCaseDetailDTO = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), FunctionalCaseDetailDTO.class);
Assertions.assertTrue(CollectionUtils.isNotEmpty(JSON.parseArray(functionalCaseDetailDTO.getSteps(), FunctionalCaseDetailDTO.class)));
}
}

View File

@ -10,7 +10,9 @@ INSERT INTO `test_plan`(`id`, `num`, `project_id`, `group_id`, `module_id`, `nam
VALUES
('plan_1', 20000, '123', 'wx_test_plan_id_3', 't_1', '测试关联', 'PREPARED', 'TEST_PLAN', NULL, 1714980158000, 'WX', 1714980158000, 'WX', 1714980158000, 1714980158000, 1714980158000, 1714980158000, '11'),
('plan_2', 25000, '1234', 'wx_test_plan_id_3', 'root', '测试关联1', 'PREPARED', 'TEST_PLAN', NULL, 1714980158000, 'WX', 1714980158000, 'WX', 1714980158000, 1714980158000, 1714980158000, 1714980158000, '11'),
('gyq_disassociate_plan_1', 25000, 'gyq_disassociate', 'wx_test_plan_id_3', 'root', '测试取消关联1', 'PREPARED', 'TEST_PLAN', NULL, 1714980158000, 'WX', 1714980158000, 'WX', 1714980158000, 1714980158000, 1714980158000, 1714980158000, '11');
('gyq_disassociate_plan_1', 25000, 'gyq_disassociate', 'wx_test_plan_id_3', 'root', '测试取消关联1', 'PREPARED', 'TEST_PLAN', NULL, 1714980158000, 'WX', 1714980158000, 'WX', 1714980158000, 1714980158000, 1714980158000, 1714980158000, '11'),
('gyq_disassociate_plan_2', 25000, 'gyq_disassociate', 'gyq_test_plan_id_1', 'root', '测试取消关联2', 'PREPARED', 'TEST_PLAN', NULL, 1714980158000, 'WX', 1714980158000, 'WX', 1714980158000, 1714980158000, 1714980158000, 1714980158000, '11');
;
INSERT INTO `test_plan_functional_case`(`id`, `test_plan_id`, `functional_case_id`, `create_time`, `create_user`, `execute_user`, `last_exec_time`, `last_exec_result`, `pos`)
VALUES
@ -19,7 +21,8 @@ VALUES
('relate_case_3', 'plan_2', 'fc_3', 1714980158000, 'admin', NULL, NULL, NULL, 1),
('gyq_disassociate_case_1', 'gyq_disassociate_plan_1', 'gyq_disassociate_fc_1', 1714980158000, 'admin', NULL, NULL, NULL, 1),
('gyq_disassociate_case_2', 'gyq_disassociate_plan_1', 'gyq_disassociate_fc_2', 1714980158000, 'admin', NULL, NULL, NULL, 1),
('gyq_disassociate_case_3', 'gyq_disassociate_plan_1', 'gyq_disassociate_fc_3', 1714980158000, 'admin', NULL, NULL, NULL, 1);
('gyq_disassociate_case_3', 'gyq_disassociate_plan_1', 'gyq_disassociate_fc_3', 1714980158000, 'admin', NULL, NULL, NULL, 1),
('gyq_disassociate_case_4', 'gyq_disassociate_plan_2', 'gyq_disassociate_fc_4', 1714980158000, 'admin', NULL, NULL, NULL, 1);
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
@ -27,7 +30,10 @@ VALUES
('fc_2', 2, 't_1', '123', '100001', '222', 'UN_REVIEWED', NULL, 'TEXT', 55000, 'v3.0.0', 'TEST_FUNCTIONAL_MINDER_CASE_ID_7', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL),
('fc_3', 3, 'root', '123', '100001', '333', 'UN_REVIEWED', NULL, 'TEXT', 55000, 'v3.0.0', 'TEST_FUNCTIONAL_MINDER_CASE_ID_7', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL),
('gyq_disassociate_fc_1', 4, 'root', 'gyq_disassociate', '100001', 'disassociate1', 'UN_REVIEWED', NULL, 'TEXT', 55000, 'v3.0.0', 'gyq_disassociate_fc_1', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL),
('gyq_disassociate_fc_2', 5, 'root', 'gyq_disassociate', '100001', 'disassociate2', 'UN_REVIEWED', NULL, 'TEXT', 55000, 'v3.0.0', 'gyq_disassociate_fc_2', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
('gyq_disassociate_fc_2', 5, 'root', 'gyq_disassociate', '100001', 'disassociate2', 'UN_REVIEWED', NULL, 'TEXT', 55000, 'v3.0.0', 'gyq_disassociate_fc_2', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL),
('gyq_disassociate_fc_4', 5, 'root', 'gyq_disassociate', '100001', 'disassociate3', 'UN_REVIEWED', NULL, 'TEXT', 55000, 'v3.0.0', 'gyq_disassociate_fc_4', '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_disassociate_fc_4', '', '', '', ' ', ' ');
INSERT INTO project_version(id, project_id, name, description, status, latest, publish_time, start_time, end_time, create_time, create_user)
@ -42,6 +48,16 @@ INSERT INTO `test_plan_module`(`id`, `project_id`, `name`, `parent_id`, `pos`, `
VALUES
('t_1', '123', '计划模块', 'NONE', 256, 1714124231051, 1714124231051, '728495172886645', '728495172886645');
INSERT INTO user_role_relation (id, user_id, role_id, source_id, organization_id, create_time, create_user)
VALUES (UUID(), 'admin', 'project_admin', 'gyq_disassociate', '100001', UNIX_TIMESTAMP() * 1000,
'admin');
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, scene, ref_id)
VALUES ('100001', 'functional_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', 'gyq_disassociate', 0, 'FUNCTIONAL', '100001');
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, scene, ref_id) VALUES ('bug-template-id', 'bug_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', 'gyq_disassociate', 0, 'BUG', 'bug-template-id');
-- 初始化项目默认模板内置字段, 项目默认模板内置字段
INSERT INTO `test_plan_case_execute_history`(`id`, `test_plan_case_id`, `case_id`, `status`, `content`, `steps`, `deleted`, `notifier`, `create_user`, `create_time`)
VALUES