feat(用例管理): 用例列表查询初版

This commit is contained in:
WangXu10 2023-11-06 13:47:34 +08:00 committed by Craftsman
parent dbfbf12ef2
commit 4b656c4843
11 changed files with 256 additions and 19 deletions

View File

@ -1,12 +1,13 @@
package io.metersphere.functional.controller; package io.metersphere.functional.controller;
import com.alibaba.excel.util.StringUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.functional.domain.FunctionalCase; import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.functional.dto.FunctionalCaseDetailDTO; import io.metersphere.functional.dto.FunctionalCaseDetailDTO;
import io.metersphere.functional.dto.FunctionalCasePageDTO;
import io.metersphere.functional.dto.FunctionalCaseVersionDTO; import io.metersphere.functional.dto.FunctionalCaseVersionDTO;
import io.metersphere.functional.request.FunctionalCaseAddRequest; import io.metersphere.functional.request.*;
import io.metersphere.functional.request.FunctionalCaseDeleteRequest;
import io.metersphere.functional.request.FunctionalCaseEditRequest;
import io.metersphere.functional.request.FunctionalCaseFollowerRequest;
import io.metersphere.functional.service.FunctionalCaseLogService; import io.metersphere.functional.service.FunctionalCaseLogService;
import io.metersphere.functional.service.FunctionalCaseNoticeService; import io.metersphere.functional.service.FunctionalCaseNoticeService;
import io.metersphere.functional.service.FunctionalCaseService; import io.metersphere.functional.service.FunctionalCaseService;
@ -18,6 +19,8 @@ import io.metersphere.system.log.annotation.Log;
import io.metersphere.system.log.constants.OperationLogType; import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.notice.annotation.SendNotice; import io.metersphere.system.notice.annotation.SendNotice;
import io.metersphere.system.notice.constants.NoticeConstants; import io.metersphere.system.notice.constants.NoticeConstants;
import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager;
import io.metersphere.system.utils.SessionUtils; import io.metersphere.system.utils.SessionUtils;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -122,4 +125,13 @@ public class FunctionalCaseController {
functionalCaseService.deleteFunctionalCase(request, userId); functionalCaseService.deleteFunctionalCase(request, userId);
} }
@PostMapping("/page")
@Operation(summary = "功能用例-用例列表查询")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
public Pager<List<FunctionalCasePageDTO>> getFunctionalCasePage(@Validated @RequestBody FunctionalCasePageRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "create_time desc");
return PageUtils.setPageInfo(page, functionalCaseService.getFunctionalCasePage(request, false));
}
} }

View File

@ -0,0 +1,21 @@
package io.metersphere.functional.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.List;
/**
* @author wx
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class CombineDTO implements Serializable {
private String id;
private List<Object> value;
private String type;
private String operator;
}

View File

@ -1,10 +1,11 @@
package io.metersphere.functional.dto; package io.metersphere.functional.dto;
import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.functional.domain.FunctionalCaseCustomField;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.List; import java.util.List;
/** /**
@ -12,9 +13,9 @@ import java.util.List;
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class FunctionalCasePageDTO implements Serializable { public class FunctionalCasePageDTO extends FunctionalCase {
@Schema(description = "自定义字段集合") @Schema(description = "自定义字段集合")
private List<CaseCustomsFieldDTO> customsFields; private List<FunctionalCaseCustomField> customsFields;
} }

View File

@ -0,0 +1,15 @@
package io.metersphere.functional.mapper;
import io.metersphere.functional.domain.FunctionalCaseCustomField;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author wx
*/
public interface ExtFunctionalCaseCustomFieldMapper {
List<FunctionalCaseCustomField> getCustomFieldByCaseIds(@Param("ids") List<String> ids);
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.functional.mapper.ExtFunctionalCaseCustomFieldMapper">
<select id="getCustomFieldByCaseIds" resultType="io.metersphere.functional.domain.FunctionalCaseCustomField">
select case_id, field_id, `value` from functional_case_custom_field where case_id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@ -1,7 +1,9 @@
package io.metersphere.functional.mapper; package io.metersphere.functional.mapper;
import io.metersphere.functional.domain.FunctionalCase; import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.functional.dto.FunctionalCasePageDTO;
import io.metersphere.functional.dto.FunctionalCaseVersionDTO; import io.metersphere.functional.dto.FunctionalCaseVersionDTO;
import io.metersphere.functional.request.FunctionalCasePageRequest;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@ -23,4 +25,5 @@ public interface ExtFunctionalCaseMapper {
List<FunctionalCase> checkCaseByModuleIds(@Param("moduleIds") List<String> deleteIds); List<FunctionalCase> checkCaseByModuleIds(@Param("moduleIds") List<String> deleteIds);
List<FunctionalCasePageDTO> list(@Param("request") FunctionalCasePageRequest request, @Param("deleted") boolean deleted);
} }

View File

@ -65,4 +65,118 @@
#{id} #{id}
</foreach> </foreach>
</select> </select>
<select id="list" resultType="io.metersphere.functional.dto.FunctionalCasePageDTO">
SELECT
id,
num,
NAME,
version_id,
create_user,
create_time,
update_user,
update_time,
review_status,
last_execute_result,
tags
FROM
functional_case
where deleted = #{deleted}
<include refid="queryWhereCondition"/>
</select>
<sql id="queryWhereCondition">
<if test="request.projectId">
and functional_case.project_id = #{request.projectId}
</if>
<if test="request.keyword != null">
and (
functional_case.name like concat('%', #{request.keyword},'%')
or functional_case.num like concat('%', #{request.keyword},'%')
or functional_case.tags like JSON_CONTAINS(tags, concat('["',#{request.keyword},'"]'))
)
</if>
<include refid="filter"/>
<include refid="combine">
<property name="condition" value="request.combine"/>
</include>
</sql>
<sql id="filter">
<if test="request.filter != null and request.filter.size() > 0">
<foreach collection="request.filter.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='review_status'">
and functional_case.review_status in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
</when>
<when test="key=='last_execute_result'">
and functional_case.last_execute_result in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
</when>
<when test="key=='version_id'">
and functional_case.version_id in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
</when>
<when test="key=='custom'">
and functional_case.id in (
select case_id from functional_case_custom_field where field_id =
#{key}
and JSON_CONTAINS(value, json_array(#{value}))
)
</when>
<when test="key=='create_user'">
and functional_case.create_user in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
</when>
</choose>
</if>
</foreach>
</if>
</sql>
<sql id="combine">
<if test="request.combine != null">
<if test='${condition}.name != null'>
and functional_case.name
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
<if test='${condition}.id != null'>
and functional_case.num
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.id"/>
</include>
</if>
<if test="${condition}.customs != null and ${condition}.customs.size() > 0">
<foreach collection="${condition}.customs" item="custom" separator="" open="" close="">
and functional_case.id ${custom.operator} (
select case_id from functional_case_custom_field where field_id = #{custom.id}
<choose>
<when test="custom.type == 'List'">
and JSON_CONTAINS(`value`, json_array(#{custom.value}))
</when>
<when test="custom.type == 'date' or custom.type == 'datetime'">
and `value`
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="custom"/>
</include>
</when>
<otherwise>
and trim(both '"' from `value`)
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="custom"/>
</include>
</otherwise>
</choose>
)
</foreach>
</if>
</if>
</sql>
</mapper> </mapper>

View File

@ -4,6 +4,7 @@ package io.metersphere.functional.service;
import io.metersphere.functional.domain.FunctionalCaseCustomField; import io.metersphere.functional.domain.FunctionalCaseCustomField;
import io.metersphere.functional.domain.FunctionalCaseCustomFieldExample; import io.metersphere.functional.domain.FunctionalCaseCustomFieldExample;
import io.metersphere.functional.dto.CaseCustomsFieldDTO; import io.metersphere.functional.dto.CaseCustomsFieldDTO;
import io.metersphere.functional.mapper.ExtFunctionalCaseCustomFieldMapper;
import io.metersphere.functional.mapper.FunctionalCaseCustomFieldMapper; import io.metersphere.functional.mapper.FunctionalCaseCustomFieldMapper;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
@ -26,6 +27,9 @@ public class FunctionalCaseCustomFieldService {
@Resource @Resource
private FunctionalCaseCustomFieldMapper functionalCaseCustomFieldMapper; private FunctionalCaseCustomFieldMapper functionalCaseCustomFieldMapper;
@Resource
private ExtFunctionalCaseCustomFieldMapper extFunctionalCaseCustomFieldMapper;
/** /**
* 保存 用例-自定义字段关系 * 保存 用例-自定义字段关系
* *
@ -99,4 +103,8 @@ public class FunctionalCaseCustomFieldService {
functionalCaseCustomFieldMapper.updateByPrimaryKeySelective(customField); functionalCaseCustomFieldMapper.updateByPrimaryKeySelective(customField);
}); });
} }
public List<FunctionalCaseCustomField> getCustomFieldByCaseIds(List<String> ids) {
return extFunctionalCaseCustomFieldMapper.getCustomFieldByCaseIds(ids);
}
} }

View File

@ -3,6 +3,7 @@ package io.metersphere.functional.service;
import io.metersphere.functional.domain.*; import io.metersphere.functional.domain.*;
import io.metersphere.functional.dto.CaseCustomsFieldDTO; import io.metersphere.functional.dto.CaseCustomsFieldDTO;
import io.metersphere.functional.dto.FunctionalCaseDetailDTO; import io.metersphere.functional.dto.FunctionalCaseDetailDTO;
import io.metersphere.functional.dto.FunctionalCasePageDTO;
import io.metersphere.functional.dto.FunctionalCaseVersionDTO; import io.metersphere.functional.dto.FunctionalCaseVersionDTO;
import io.metersphere.functional.mapper.ExtFunctionalCaseMapper; import io.metersphere.functional.mapper.ExtFunctionalCaseMapper;
import io.metersphere.functional.mapper.FunctionalCaseBlobMapper; import io.metersphere.functional.mapper.FunctionalCaseBlobMapper;
@ -11,6 +12,7 @@ import io.metersphere.functional.mapper.FunctionalCaseMapper;
import io.metersphere.functional.request.FunctionalCaseAddRequest; import io.metersphere.functional.request.FunctionalCaseAddRequest;
import io.metersphere.functional.request.FunctionalCaseDeleteRequest; import io.metersphere.functional.request.FunctionalCaseDeleteRequest;
import io.metersphere.functional.request.FunctionalCaseEditRequest; import io.metersphere.functional.request.FunctionalCaseEditRequest;
import io.metersphere.functional.request.FunctionalCasePageRequest;
import io.metersphere.functional.result.FunctionalCaseResultCode; import io.metersphere.functional.result.FunctionalCaseResultCode;
import io.metersphere.project.service.ProjectTemplateService; import io.metersphere.project.service.ProjectTemplateService;
import io.metersphere.sdk.constants.ApplicationNumScope; import io.metersphere.sdk.constants.ApplicationNumScope;
@ -31,10 +33,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -362,4 +361,30 @@ public class FunctionalCaseService {
List<FunctionalCaseVersionDTO> list = extFunctionalCaseMapper.getFunctionalCaseByRefId(functionalCase.getRefId()); List<FunctionalCaseVersionDTO> list = extFunctionalCaseMapper.getFunctionalCaseByRefId(functionalCase.getRefId());
return list; return list;
} }
/**
* 列表查询
*
* @param request
* @return
*/
public List<FunctionalCasePageDTO> getFunctionalCasePage(FunctionalCasePageRequest request, Boolean deleted) {
List<FunctionalCasePageDTO> functionalCaseLists = extFunctionalCaseMapper.list(request, deleted);
if (CollectionUtils.isEmpty(functionalCaseLists)) {
return new ArrayList<>();
}
//处理自定义字段值
return handleCustomFieldsAnd(functionalCaseLists);
}
private List<FunctionalCasePageDTO> handleCustomFieldsAnd(List<FunctionalCasePageDTO> functionalCaseLists) {
List<String> ids = functionalCaseLists.stream().map(FunctionalCasePageDTO::getId).collect(Collectors.toList());
List<FunctionalCaseCustomField> customFields = functionalCaseCustomFieldService.getCustomFieldByCaseIds(ids);
Map<String, List<FunctionalCaseCustomField>> collect = customFields.stream().collect(Collectors.groupingBy(FunctionalCaseCustomField::getCaseId));
functionalCaseLists.forEach(functionalCasePageDTO -> {
functionalCasePageDTO.setCustomsFields(collect.get(functionalCasePageDTO.getId()));
});
return functionalCaseLists;
}
} }

View File

@ -2,10 +2,7 @@ package io.metersphere.functional.controller;
import io.metersphere.functional.domain.FunctionalCase; import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.functional.dto.CaseCustomsFieldDTO; import io.metersphere.functional.dto.CaseCustomsFieldDTO;
import io.metersphere.functional.request.FunctionalCaseAddRequest; import io.metersphere.functional.request.*;
import io.metersphere.functional.request.FunctionalCaseDeleteRequest;
import io.metersphere.functional.request.FunctionalCaseEditRequest;
import io.metersphere.functional.request.FunctionalCaseFollowerRequest;
import io.metersphere.functional.result.FunctionalCaseResultCode; import io.metersphere.functional.result.FunctionalCaseResultCode;
import io.metersphere.functional.utils.FileBaseUtils; import io.metersphere.functional.utils.FileBaseUtils;
import io.metersphere.project.domain.Notification; import io.metersphere.project.domain.Notification;
@ -32,10 +29,7 @@ import org.springframework.test.web.servlet.MvcResult;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -49,6 +43,7 @@ public class FunctionalCaseControllerTests extends BaseTest {
public static final String FUNCTIONAL_CASE_EDIT_FOLLOWER_URL = "/functional/case/edit/follower"; public static final String FUNCTIONAL_CASE_EDIT_FOLLOWER_URL = "/functional/case/edit/follower";
public static final String FUNCTIONAL_CASE_FOLLOWER_URL = "/functional/case/follower/"; public static final String FUNCTIONAL_CASE_FOLLOWER_URL = "/functional/case/follower/";
public static final String FUNCTIONAL_CASE_DELETE_URL = "/functional/case/delete"; public static final String FUNCTIONAL_CASE_DELETE_URL = "/functional/case/delete";
public static final String FUNCTIONAL_CASE_LIST_URL = "/functional/case/page";
@Resource @Resource
private NotificationMapper notificationMapper; private NotificationMapper notificationMapper;
@ -255,6 +250,36 @@ public class FunctionalCaseControllerTests extends BaseTest {
@Test @Test
@Order(5) @Order(5)
public void testGetPageList() throws Exception {
FunctionalCasePageRequest request = new FunctionalCasePageRequest();
request.setProjectId("test_project_id");
request.setCurrent(1);
request.setPageSize(10);
this.requestPost(FUNCTIONAL_CASE_LIST_URL, request);
request.setProjectId(DEFAULT_PROJECT_ID);
request.setSort(new HashMap<>() {{
put("createTime", "desc");
}});
MvcResult mvcResult = this.requestPostWithOkAndReturn(FUNCTIONAL_CASE_LIST_URL, request);
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Assertions.assertNotNull(resultHolder);
//自定义字段 测试
Map<String,Object> map = new HashMap<>();
map.put("customs",Arrays.asList(new LinkedHashMap(){{
put("id","TEST_FIELD_ID");
put("operator","in");
put("value","222");
put("type","List");
}}));
request.setCombine(map);
this.requestPostWithOkAndReturn(FUNCTIONAL_CASE_LIST_URL, request);
}
@Test
@Order(6)
public void testDeleteFunctionalCase() throws Exception { public void testDeleteFunctionalCase() throws Exception {
FunctionalCaseDeleteRequest request = new FunctionalCaseDeleteRequest(); FunctionalCaseDeleteRequest request = new FunctionalCaseDeleteRequest();
request.setId("TEST_FUNCTIONAL_CASE_ID"); request.setId("TEST_FUNCTIONAL_CASE_ID");

View File

@ -21,6 +21,7 @@ INSERT INTO functional_case_blob(id, steps, text_description, expected_result, p
INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('TEST_FUNCTIONAL_CASE_ID', '100548878725546079', '22'); INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('TEST_FUNCTIONAL_CASE_ID', '100548878725546079', '22');
INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('TEST_FUNCTIONAL_CASE_ID', 'TEST_FIELD_ID', '["222","333"]');
INSERT INTO functional_case_attachment(id, case_id, file_id, file_name, size, local, create_user, create_time) VALUES ('TEST_CASE_ATTACHMENT_ID', 'TEST_FUNCTIONAL_CASE_ID', '100548878725546079', '测试', 1, b'1', 'admin', 1698058347559); INSERT INTO functional_case_attachment(id, case_id, file_id, file_name, size, local, create_user, create_time) VALUES ('TEST_CASE_ATTACHMENT_ID', 'TEST_FUNCTIONAL_CASE_ID', '100548878725546079', '测试', 1, b'1', 'admin', 1698058347559);