refactor(测试计划): 更新测试计划跟踪人表名,完善add接口,以及对应的测试用例

更新测试计划跟踪人表名,完善add接口,以及对应的测试用例
This commit is contained in:
song-tianyang 2023-06-01 12:15:17 +08:00 committed by 刘瑞斌
parent af2e346c1d
commit 24d30b7f52
13 changed files with 294 additions and 64 deletions

View File

@ -1,5 +1,56 @@
-- set innodb lock wait timeout
SET SESSION innodb_lock_wait_timeout = 7200;
DROP TABLE IF EXISTS test_plan;
CREATE TABLE test_plan(
`id` VARCHAR(50) NOT NULL COMMENT 'ID' ,
`project_id` VARCHAR(50) NOT NULL COMMENT '测试计划所属项目' ,
`parent_id` VARCHAR(50) NOT NULL COMMENT '测试计划父ID;测试计划要改为树结构。最上层的为root其余则是父节点ID' ,
`name` VARCHAR(255) NOT NULL COMMENT '测试计划名称' ,
`status` VARCHAR(20) NOT NULL COMMENT '测试计划状态;进行中/未开始/已完成/已结束/已归档' ,
`stage` VARCHAR(30) NOT NULL COMMENT '测试阶段' ,
`tags` VARCHAR(500) COMMENT '标签' ,
`create_time` BIGINT NOT NULL COMMENT '创建时间' ,
`create_user` VARCHAR(50) NOT NULL COMMENT '创建人' ,
`update_time` BIGINT COMMENT '更新时间' ,
`update_user` VARCHAR(50) COMMENT '更新人' ,
`planned_start_time` BIGINT COMMENT '计划开始时间' ,
`planned_end_time` BIGINT COMMENT '计划结束时间' ,
`actual_start_time` BIGINT COMMENT '实际开始时间' ,
`actual_end_time` BIGINT COMMENT '实际结束时间' ,
`description` VARCHAR(2000) COMMENT '描述' ,
PRIMARY KEY (id)
) COMMENT = '测试计划';
CREATE INDEX idx_parent_id ON test_plan(project_id);
CREATE INDEX idx_project_id ON test_plan(project_id);
CREATE INDEX idx_create_user ON test_plan(create_user);
CREATE INDEX idx_status ON test_plan(status);
DROP TABLE IF EXISTS test_plan_follower;
CREATE TABLE test_plan_follower(
`test_plan_id` VARCHAR(50) NOT NULL COMMENT '测试计划ID;联合主键' ,
`user_id` VARCHAR(50) NOT NULL COMMENT '用户ID;联合主键' ,
PRIMARY KEY (test_plan_id,user_id)
) COMMENT = '测试计划关注人';
DROP TABLE IF EXISTS test_plan_principal;
CREATE TABLE test_plan_principal(
`test_plan_id` VARCHAR(50) NOT NULL COMMENT '测试计划ID' ,
`user_id` VARCHAR(50) NOT NULL COMMENT '用户ID' ,
PRIMARY KEY (test_plan_id,user_id)
) COMMENT = '测试计划责任人';
DROP TABLE IF EXISTS test_plan_config;
CREATE TABLE test_plan_config(
`test_plan_id` VARCHAR(50) NOT NULL COMMENT '测试计划ID' ,
`run_mode_config` TEXT NOT NULL COMMENT '运行模式' ,
`automatic_status_update` BIT(1) NOT NULL DEFAULT 0 COMMENT '是否自定更新功能用例状态' ,
`repeat_case` BIT(1) NOT NULL DEFAULT 0 COMMENT '是否允许重复添加用例' ,
`pass_threshold` INT(3) NOT NULL DEFAULT 100 COMMENT '测试计划通过阈值;0-100' ,
PRIMARY KEY (test_plan_id)
) COMMENT = '测试计划配置';
-- set innodb lock wait timeout to default
SET SESSION innodb_lock_wait_timeout = DEFAULT;

View File

@ -9,15 +9,15 @@ import java.io.Serializable;
import lombok.Data;
@Data
public class TestPlanFollow implements Serializable {
public class TestPlanFollower implements Serializable {
@Schema(title = "测试计划ID;联合主键", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_follow.test_plan_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_follow.test_plan_id.length_range}", groups = {Created.class, Updated.class})
@NotBlank(message = "{test_plan_follower.test_plan_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_follower.test_plan_id.length_range}", groups = {Created.class, Updated.class})
private String testPlanId;
@Schema(title = "用户ID;联合主键", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_follow.user_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_follow.user_id.length_range}", groups = {Created.class, Updated.class})
@NotBlank(message = "{test_plan_follower.user_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_follower.user_id.length_range}", groups = {Created.class, Updated.class})
private String userId;
private static final long serialVersionUID = 1L;

View File

@ -3,14 +3,14 @@ package io.metersphere.plan.domain;
import java.util.ArrayList;
import java.util.List;
public class TestPlanFollowExample {
public class TestPlanFollowerExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public TestPlanFollowExample() {
public TestPlanFollowerExample() {
oredCriteria = new ArrayList<Criteria>();
}

View File

@ -1,24 +0,0 @@
package io.metersphere.plan.mapper;
import io.metersphere.plan.domain.TestPlanFollow;
import io.metersphere.plan.domain.TestPlanFollowExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface TestPlanFollowMapper {
long countByExample(TestPlanFollowExample example);
int deleteByExample(TestPlanFollowExample example);
int deleteByPrimaryKey(@Param("testPlanId") String testPlanId, @Param("userId") String userId);
int insert(TestPlanFollow record);
int insertSelective(TestPlanFollow record);
List<TestPlanFollow> selectByExample(TestPlanFollowExample example);
int updateByExampleSelective(@Param("record") TestPlanFollow record, @Param("example") TestPlanFollowExample example);
int updateByExample(@Param("record") TestPlanFollow record, @Param("example") TestPlanFollowExample example);
}

View File

@ -0,0 +1,24 @@
package io.metersphere.plan.mapper;
import io.metersphere.plan.domain.TestPlanFollower;
import io.metersphere.plan.domain.TestPlanFollowerExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface TestPlanFollowerMapper {
long countByExample(TestPlanFollowerExample example);
int deleteByExample(TestPlanFollowerExample example);
int deleteByPrimaryKey(@Param("testPlanId") String testPlanId, @Param("userId") String userId);
int insert(TestPlanFollower record);
int insertSelective(TestPlanFollower record);
List<TestPlanFollower> selectByExample(TestPlanFollowerExample example);
int updateByExampleSelective(@Param("record") TestPlanFollower record, @Param("example") TestPlanFollowerExample example);
int updateByExample(@Param("record") TestPlanFollower record, @Param("example") TestPlanFollowerExample example);
}

View File

@ -1,7 +1,7 @@
<?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.plan.mapper.TestPlanFollowMapper">
<resultMap id="BaseResultMap" type="io.metersphere.plan.domain.TestPlanFollow">
<mapper namespace="io.metersphere.plan.mapper.TestPlanFollowerMapper">
<resultMap id="BaseResultMap" type="io.metersphere.plan.domain.TestPlanFollower">
<id column="test_plan_id" jdbcType="VARCHAR" property="testPlanId" />
<id column="user_id" jdbcType="VARCHAR" property="userId" />
</resultMap>
@ -66,13 +66,13 @@
<sql id="Base_Column_List">
test_plan_id, user_id
</sql>
<select id="selectByExample" parameterType="io.metersphere.plan.domain.TestPlanFollowExample" resultMap="BaseResultMap">
<select id="selectByExample" parameterType="io.metersphere.plan.domain.TestPlanFollowerExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from test_plan_follow
from test_plan_follower
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
@ -81,22 +81,22 @@
</if>
</select>
<delete id="deleteByPrimaryKey" parameterType="map">
delete from test_plan_follow
delete from test_plan_follower
where test_plan_id = #{testPlanId,jdbcType=VARCHAR}
and user_id = #{userId,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.plan.domain.TestPlanFollowExample">
delete from test_plan_follow
<delete id="deleteByExample" parameterType="io.metersphere.plan.domain.TestPlanFollowerExample">
delete from test_plan_follower
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.plan.domain.TestPlanFollow">
insert into test_plan_follow (test_plan_id, user_id)
<insert id="insert" parameterType="io.metersphere.plan.domain.TestPlanFollower">
insert into test_plan_follower (test_plan_id, user_id)
values (#{testPlanId,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.plan.domain.TestPlanFollow">
insert into test_plan_follow
<insert id="insertSelective" parameterType="io.metersphere.plan.domain.TestPlanFollower">
insert into test_plan_follower
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="testPlanId != null">
test_plan_id,
@ -114,14 +114,14 @@
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.plan.domain.TestPlanFollowExample" resultType="java.lang.Long">
select count(*) from test_plan_follow
<select id="countByExample" parameterType="io.metersphere.plan.domain.TestPlanFollowerExample" resultType="java.lang.Long">
select count(*) from test_plan_follower
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update test_plan_follow
update test_plan_follower
<set>
<if test="record.testPlanId != null">
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
@ -135,7 +135,7 @@
</if>
</update>
<update id="updateByExample" parameterType="map">
update test_plan_follow
update test_plan_follower
set test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
user_id = #{record.userId,jdbcType=VARCHAR}
<if test="_parameter != null">

View File

@ -53,28 +53,28 @@
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 模型对象 -->
<javaModelGenerator targetPackage="io.metersphere.issue.domain" targetProject="src/main/java">
<javaModelGenerator targetPackage="io.metersphere.plan.domain" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- XML映射文件 -->
<sqlMapGenerator targetPackage="io.metersphere.issue.mapper" targetProject="src/main/java">
<sqlMapGenerator targetPackage="io.metersphere.plan.mapper" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 接口 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="io.metersphere.issue.mapper"
<javaClientGenerator type="XMLMAPPER" targetPackage="io.metersphere.plan.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!--要生成的数据库表 -->
<table tableName="issue" />
<table tableName="issue_blob" />
<table tableName="issues_functional_case" />
<table tableName="issue_attachment" />
<table tableName="issue_comment" />
<table tableName="issue_follow" />
<table tableName="custom_field_issues" />
<table tableName="test_plan_follower" />
<!-- <table tableName="issue_blob" />-->
<!-- <table tableName="issues_functional_case" />-->
<!-- <table tableName="issue_attachment" />-->
<!-- <table tableName="issue_comment" />-->
<!-- <table tableName="issue_follow" />-->
<!-- <table tableName="custom_field_issues" />-->
<!-- 要忽略的字段-->

View File

@ -1,6 +1,6 @@
package io.metersphere.plan.controller;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.dto.TestPlanDTO;
import io.metersphere.plan.service.TestPlanService;
import io.metersphere.validation.groups.Created;
import jakarta.annotation.Resource;
@ -17,7 +17,7 @@ public class TestPlanController {
private TestPlanService testPlanService;
@PostMapping("/add")
public boolean addUser(@Validated({Created.class}) @RequestBody TestPlan testPlan) {
public TestPlanDTO addUser(@Validated({Created.class}) @RequestBody TestPlanDTO testPlan) {
return testPlanService.add(testPlan);
}
}

View File

@ -0,0 +1,16 @@
package io.metersphere.plan.dto;
import io.metersphere.plan.domain.TestPlan;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class TestPlanDTO extends TestPlan {
@Schema(title = "测试计划责任人", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private List<String> principals;
@Schema(title = "测试计划关注人")
private List<String> followers;
}

View File

@ -0,0 +1,23 @@
package io.metersphere.plan.service;
import io.metersphere.plan.domain.TestPlanFollower;
import io.metersphere.plan.mapper.TestPlanFollowerMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanFollowerService {
@Resource
TestPlanFollowerMapper testPlanFollowerMapper;
public void batchSave(List<TestPlanFollower> testPlanFollowerList) {
for (TestPlanFollower testPlanFollower : testPlanFollowerList) {
testPlanFollowerMapper.insert(testPlanFollower);
}
}
}

View File

@ -0,0 +1,24 @@
package io.metersphere.plan.service;
import io.metersphere.plan.domain.TestPlanPrincipal;
import io.metersphere.plan.mapper.TestPlanPrincipalMapper;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanPrincipalService {
@Resource
TestPlanPrincipalMapper testPlanPrincipalMapper;
public void batchSave(@NotEmpty List<TestPlanPrincipal> testPlanPrincipalList) {
for (TestPlanPrincipal testPlanPrincipal : testPlanPrincipalList) {
testPlanPrincipalMapper.insert(testPlanPrincipal);
}
}
}

View File

@ -1,14 +1,61 @@
package io.metersphere.plan.service;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanFollower;
import io.metersphere.plan.domain.TestPlanPrincipal;
import io.metersphere.plan.dto.TestPlanDTO;
import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.sdk.util.BeanUtils;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanService {
@Resource
private TestPlanMapper testPlanMapper;
public boolean add(TestPlan testPlan) {
return testPlan == null;
@Resource
private TestPlanPrincipalService testPlanPrincipalService;
@Resource
private TestPlanFollowerService testPlanFollowerService;
public TestPlanDTO add(@NotNull TestPlanDTO testPlanDTO) {
TestPlan testPlan = new TestPlan();
BeanUtils.copyBean(testPlan, testPlanDTO);
testPlan.setId(UUID.randomUUID().toString());
//todo SongTianyang:暂时没有SessionUtil创建人先根据前台传值保存
testPlan.setCreateTime(System.currentTimeMillis());
testPlanMapper.insert(testPlan);
if (CollectionUtils.isNotEmpty(testPlanDTO.getFollowers())) {
List<TestPlanFollower> testPlanFollowerList = new ArrayList<>();
for (String follower : testPlanDTO.getFollowers()) {
TestPlanFollower testPlanFollower = new TestPlanFollower();
testPlanFollower.setTestPlanId(testPlan.getId());
testPlanFollower.setUserId(follower);
testPlanFollowerList.add(testPlanFollower);
}
testPlanFollowerService.batchSave(testPlanFollowerList);
}
if (CollectionUtils.isNotEmpty(testPlanDTO.getPrincipals())) {
List<TestPlanPrincipal> testPlanPrincipalList = new ArrayList<>();
for (String principal : testPlanDTO.getPrincipals()) {
TestPlanPrincipal testPlanPrincipal = new TestPlanPrincipal();
testPlanPrincipal.setTestPlanId(testPlan.getId());
testPlanPrincipal.setUserId(principal);
testPlanPrincipalList.add(testPlanPrincipal);
}
testPlanPrincipalService.batchSave(testPlanPrincipalList);
}
return testPlanDTO;
}
}

View File

@ -1,6 +1,7 @@
package io.metersphere.plan.controller;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.dto.TestPlanDTO;
import io.metersphere.sdk.util.JSON;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.MethodOrderer;
@ -13,6 +14,9 @@ import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.util.ArrayList;
import java.util.List;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -25,10 +29,8 @@ public class TestPlanControllerTests {
@Resource
private MockMvc mockMvc;
@Test
@Order(1)
public void testAddUserTrue() throws Exception {
TestPlan testPlan = new TestPlan();
private TestPlanDTO getSimpleTestPlan() {
TestPlanDTO testPlan = new TestPlanDTO();
testPlan.setId("test");
testPlan.setName("test");
testPlan.setProjectId("1");
@ -36,7 +38,26 @@ public class TestPlanControllerTests {
testPlan.setCreateUser("JianGuo");
testPlan.setStage("Smock");
testPlan.setStatus("PREPARE");
testPlan.setCreateUser("JianGuo");
return testPlan;
}
@Test
@Order(1)
public void testAdd1() throws Exception {
TestPlanDTO testPlan = this.getSimpleTestPlan();
List<String> followerList = new ArrayList<>();
followerList.add("JianGuo");
followerList.add("SongGuoyu");
followerList.add("SongYingyu");
followerList.add("SongFanti");
testPlan.setFollowers(followerList);
List<String> participantList = new ArrayList<>();
participantList.add("JianGuo");
participantList.add("SongGuoyu");
testPlan.setPrincipals(participantList);
mockMvc.perform(MockMvcRequestBuilders.post("/test-plan/add")
.content(JSON.toJSONString(testPlan))
@ -47,6 +68,54 @@ public class TestPlanControllerTests {
@Test
@Order(2)
public void testAdd2() throws Exception {
TestPlanDTO testPlan = this.getSimpleTestPlan();
List<String> followerList = new ArrayList<>();
followerList.add("JianGuo");
followerList.add("SongGuoyu");
followerList.add("SongYingyu");
followerList.add("SongFanti");
testPlan.setFollowers(followerList);
mockMvc.perform(MockMvcRequestBuilders.post("/test-plan/add")
.content(JSON.toJSONString(testPlan))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andDo(print());
}
@Test
@Order(2)
public void testAdd3() throws Exception {
TestPlanDTO testPlan = this.getSimpleTestPlan();
List<String> participantList = new ArrayList<>();
participantList.add("JianGuo");
participantList.add("SongGuoyu");
testPlan.setPrincipals(participantList);
mockMvc.perform(MockMvcRequestBuilders.post("/test-plan/add")
.content(JSON.toJSONString(testPlan))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andDo(print());
}
@Test
@Order(4)
public void testAdd4() throws Exception {
TestPlanDTO testPlan = this.getSimpleTestPlan();
mockMvc.perform(MockMvcRequestBuilders.post("/test-plan/add")
.content(JSON.toJSONString(testPlan))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andDo(print());
}
@Test
@Order(5)
public void testAddUserFalse() throws Exception {
TestPlan testPlan = new TestPlan();
testPlan.setName("test");