!133 fix(supervision): 修正 InspectCloseoutFlowTest 角色参数匹配实际调用
* fix(supervision): 修正 InspectCloseoutFlowTest 角色参数匹配实际调用 * test(fixcontact): 新增流程表达式/监听器/Service 单测,fixcontact 可测代码接近全覆盖 * refactor(fixcontact): 提炼上两级解析与部门ID清洗纯函数,监听器依赖注入化 * chore(bpm): 安装 JaCoCo 覆盖率插件并修复构建链(补齐 base-core 依赖、排除环境依赖测试)
This commit is contained in:
@@ -31,6 +31,11 @@
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- 基础核心(代码直接使用 base-core 的 Result 等) -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-base-core</artifactId>
|
||||
</dependency>
|
||||
<!-- system单体 api-->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
@@ -189,4 +194,20 @@
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- 排除 airag/test 包:历史遗留的调试型测试(TestFlows 连本地 7008 AI 服务、TestFileParse 依赖测试文件),
|
||||
不属于可自动化单测,避免 mvn test 全量时因环境缺失而失败;IDE 中仍可手动单独运行 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/airag/test/**</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -57,6 +57,11 @@
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- 基础核心(代码直接使用 base-core 的 Result/SymbolConstant/QueryGenerator 等) -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-base-core</artifactId>
|
||||
</dependency>
|
||||
<!-- 单体system api -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
|
||||
@@ -30,5 +30,21 @@
|
||||
<artifactId>jeecg-system-biz</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- flowregression 是 E2E 回归测试(HTTP 驱动真实后端 localhost:8080),
|
||||
后端未启动时必然失败,从全量 mvn test 排除;需要时启动后端或 -Dtest=*RegressionTest 单独跑 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/flowregression/**</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
|
||||
+4
-20
@@ -258,7 +258,7 @@ public class FixContactFlow {
|
||||
execution.getProcessInstanceId());
|
||||
return null;
|
||||
}
|
||||
return deptVar.toString().replace("[", "").replace("]", "").trim();
|
||||
return FixContactFlowSupport.cleanDeptId(deptVar);
|
||||
}
|
||||
|
||||
// ${fixContactFlow.getCurrentDeptLeaderList(execution, deptId)}
|
||||
@@ -357,14 +357,7 @@ public class FixContactFlow {
|
||||
if (value == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
String str = value.toString();
|
||||
if (StringUtils.isBlank(str)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Arrays.stream(str.split(","))
|
||||
.map(String::trim)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toList());
|
||||
return FixContactFlowSupport.splitToTrimmedList(value.toString());
|
||||
}
|
||||
|
||||
// ${fixContactFlow.getVarAsListCount(execution, varName)}
|
||||
@@ -374,13 +367,7 @@ public class FixContactFlow {
|
||||
|
||||
// ${fixContactFlow.getListSize(data)}
|
||||
public int getListSize(String data) {
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
return 0;
|
||||
}
|
||||
return (int) Arrays.stream(data.split(","))
|
||||
.map(String::trim)
|
||||
.filter(StringUtils::isNotEmpty)
|
||||
.count();
|
||||
return FixContactFlowSupport.countTokens(data);
|
||||
}
|
||||
|
||||
// ${fixContactFlow.getIsNeedLeaderApprove(execution)}
|
||||
@@ -619,10 +606,7 @@ public class FixContactFlow {
|
||||
if (StringUtils.isBlank(rawValue)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> result = Arrays.stream(rawValue.split(","))
|
||||
.map(String::trim)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toList());
|
||||
List<String> result = FixContactFlowSupport.splitToTrimmedList(rawValue);
|
||||
log.info("【定点联系-流程表达式】{} 解析结果: {}", logLabel, result);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package org.jeecg.modules.supervision.fixcontact.flow;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 定点联系流程表达式纯逻辑支撑(无外部依赖,可独立测试)。
|
||||
*
|
||||
* 规则(提炼自 FixContactFlow 内联重复逻辑):
|
||||
* - splitToTrimmedList:逗号分割 → trim → 过滤空白元素
|
||||
* - countTokens:分割后有效元素个数
|
||||
* - cleanDeptId:流程变量部门 ID 清洗(去 [] 与首尾空白)
|
||||
*/
|
||||
public final class FixContactFlowSupport {
|
||||
|
||||
private FixContactFlowSupport() {
|
||||
}
|
||||
|
||||
public static List<String> splitToTrimmedList(String raw) {
|
||||
if (StringUtils.isBlank(raw)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Arrays.stream(raw.split(","))
|
||||
.map(String::trim)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static int countTokens(String raw) {
|
||||
return splitToTrimmedList(raw).size();
|
||||
}
|
||||
|
||||
public static String cleanDeptId(Object raw) {
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
return raw.toString().replace("[", "").replace("]", "").trim();
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package org.jeecg.modules.supervision.fixcontact.listener;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* 定点联系流程审批辅助逻辑(纯函数,无外部依赖,可独立测试)。
|
||||
*
|
||||
* 规则:部门领导审批后,领导变量写入"上两级"执行实例;
|
||||
* 存在第二层父级存第二层(大会签容器/外层作用域),否则存第一层。
|
||||
*/
|
||||
public final class FixContactApprovalHelper {
|
||||
|
||||
private FixContactApprovalHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析领导变量应写入的目标执行实例 ID。
|
||||
*
|
||||
* @param parentId 第一层父级执行实例 ID
|
||||
* @param grandParentId 第二层父级执行实例 ID(可能为空)
|
||||
* @return 有第二层返回 grandParentId;否则返回 parentId;parentId 为空返回 null(调用方跳过)
|
||||
*/
|
||||
public static String resolveTargetExecutionId(String parentId, String grandParentId) {
|
||||
if (StringUtils.isBlank(parentId)) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.isNotBlank(grandParentId)) {
|
||||
return grandParentId;
|
||||
}
|
||||
return parentId;
|
||||
}
|
||||
}
|
||||
+6
-9
@@ -1,13 +1,14 @@
|
||||
package org.jeecg.modules.supervision.fixcontact.listener;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.delegate.TaskListener;
|
||||
import org.flowable.engine.runtime.Execution;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.jeecg.modules.supervision.fixcontact.constant.FixContactConstant;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -16,16 +17,13 @@ import org.springframework.stereotype.Component;
|
||||
*/
|
||||
@Slf4j
|
||||
@Component("FixContactDeptLeaderApproveListener")
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
public class FixContactDeptLeaderApproveListener implements TaskListener {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String VARIABLE_NAME = FixContactConstant.FlowVarName.TEM_IMPL_LEADER;
|
||||
|
||||
private static RuntimeService runtimeService;
|
||||
|
||||
static {
|
||||
runtimeService = SpringContextUtils.getBean(RuntimeService.class);
|
||||
}
|
||||
private final RuntimeService runtimeService;
|
||||
|
||||
@Override
|
||||
public void notify(DelegateTask delegateTask) {
|
||||
@@ -64,9 +62,8 @@ public class FixContactDeptLeaderApproveListener implements TaskListener {
|
||||
if (parentExecution == null) {
|
||||
return;
|
||||
}
|
||||
String grandParentId = parentExecution.getParentId();
|
||||
// 有第二层父级则存入第二层(大会签容器/外层作用域),否则存入第一层
|
||||
String targetId = StringUtils.isNotBlank(grandParentId) ? grandParentId : parentId;
|
||||
// 有第二层父级则存入第二层(大会签容器/外层作用域),否则存入第一层(规则见 FixContactApprovalHelper)
|
||||
String targetId = FixContactApprovalHelper.resolveTargetExecutionId(parentId, parentExecution.getParentId());
|
||||
try {
|
||||
runtimeService.setVariableLocal(targetId, VARIABLE_NAME, assignee);
|
||||
log.info("【定点联系-部门领导审批监听器】已存入上两级局部变量, targetExecutionId: {}, variableName: {}, assignee: {}",
|
||||
|
||||
+2
-1
@@ -8,6 +8,7 @@ import org.flowable.engine.delegate.TaskListener;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
import org.jeecg.modules.supervision.fixcontact.constant.FixContactConstant;
|
||||
import org.jeecg.modules.supervision.fixcontact.entity.FixedContact20260730;
|
||||
import org.jeecg.modules.supervision.fixcontact.flow.FixContactFlowSupport;
|
||||
import org.jeecg.modules.supervision.fixcontact.service.IFixedContact20260730Service;
|
||||
import org.jeecg.modules.supervision.xispeak.entity.DeptApproveDetail;
|
||||
import org.jeecg.modules.supervision.xispeak.entity.DeptApproveDetailMap;
|
||||
@@ -74,7 +75,7 @@ public class FixContactWorkerApproveListener implements TaskListener {
|
||||
log.warn("【定点联系-经办人会签监听器】未获取到子流程当前部门ID,跳过记录经办人, taskId: {}", delegateTask.getId());
|
||||
return;
|
||||
}
|
||||
String deptId = rawDeptVar.toString().replace("[", "").replace("]", "").trim();
|
||||
String deptId = FixContactFlowSupport.cleanDeptId(rawDeptVar);
|
||||
|
||||
FixedContact20260730 fixedContact = fixedContact20260730Service.getByIdForUpdate(rawBusinessKey.toString());
|
||||
if (fixedContact == null) {
|
||||
|
||||
+3
-3
@@ -124,7 +124,7 @@ class InspectCloseoutFlowTest {
|
||||
@Test
|
||||
void getDqDeptLdUserIdList_shouldReturnUserList() {
|
||||
List<String> users = List.of("dq_user1");
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi("dept-dq", "role-jj-worker"))
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi("dept-dq", "role-ld"))
|
||||
.thenReturn(users);
|
||||
|
||||
assertEquals(users, flow.getDqDeptLdUserIdList());
|
||||
@@ -132,7 +132,7 @@ class InspectCloseoutFlowTest {
|
||||
|
||||
@Test
|
||||
void getDqDeptLdUserIdListLength_shouldReturnCount() {
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi("dept-dq", "role-jj-worker"))
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi("dept-dq", "role-ld"))
|
||||
.thenReturn(List.of("user1", "user2"));
|
||||
|
||||
assertEquals(2, flow.getDqDeptLdUserIdListLength());
|
||||
@@ -140,7 +140,7 @@ class InspectCloseoutFlowTest {
|
||||
|
||||
@Test
|
||||
void getDqDeptLdUserIdListLength_shouldReturnZeroWhenEmpty() {
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi("dept-dq", "role-jj-worker"))
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi("dept-dq", "role-ld"))
|
||||
.thenReturn(Collections.emptyList());
|
||||
|
||||
assertEquals(0, flow.getDqDeptLdUserIdListLength());
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package org.jeecg.modules.supervision.fixcontact.flow;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.NullAndEmptySource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
/**
|
||||
* FixContactFlowSupport 纯函数规则测试(TDD 红-绿-重构,阶段 A 示范)。
|
||||
*
|
||||
* 业务规则(来自 FixContactFlow 内联逻辑,3 处重复的逗号分割 + 部门 ID 清洗):
|
||||
* - splitToTrimmedList:逗号分割 → 去首尾空白 → 过滤空白元素(null/空 → 空列表)
|
||||
* - countTokens:分割后元素个数(等价于 splitToTrimmedList().size())
|
||||
* - cleanDeptId:执行实例部门变量清洗(去掉 [] 与首尾空白,与 XiSpeak 监听器同款规则)
|
||||
*/
|
||||
class FixContactFlowSupportTest {
|
||||
|
||||
// ============ splitToTrimmedList:正常路径 ============
|
||||
|
||||
@Test
|
||||
void should_split_multi_tokens() {
|
||||
assertEquals(List.of("a", "b", "c"), FixContactFlowSupport.splitToTrimmedList("a,b,c"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_trim_tokens_with_spaces() {
|
||||
// 逗号前后有空格:逐 token trim
|
||||
assertEquals(List.of("a", "b"), FixContactFlowSupport.splitToTrimmedList(" a , b "));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_single_token() {
|
||||
assertEquals(List.of("a"), FixContactFlowSupport.splitToTrimmedList("a"));
|
||||
}
|
||||
|
||||
// ============ splitToTrimmedList:边界路径 ============
|
||||
|
||||
@Test
|
||||
void should_filter_empty_tokens() {
|
||||
// 空元素(连续逗号/全空白元素)被过滤
|
||||
assertEquals(List.of("a", "b"), FixContactFlowSupport.splitToTrimmedList("a,,b"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@NullAndEmptySource
|
||||
@ValueSource(strings = {" ", " ", " , , "})
|
||||
void should_return_empty_list_when_no_valid_token(String raw) {
|
||||
assertEquals(List.of(), FixContactFlowSupport.splitToTrimmedList(raw));
|
||||
}
|
||||
|
||||
// ============ countTokens:正常 + 边界 ============
|
||||
|
||||
@Test
|
||||
void should_count_tokens() {
|
||||
assertEquals(3, FixContactFlowSupport.countTokens("a,b,c"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_count_trimmed_tokens() {
|
||||
assertEquals(2, FixContactFlowSupport.countTokens(" a , b "));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@NullAndEmptySource
|
||||
@ValueSource(strings = {" ", " , , "})
|
||||
void should_return_zero_when_no_valid_token(String raw) {
|
||||
assertEquals(0, FixContactFlowSupport.countTokens(raw));
|
||||
}
|
||||
|
||||
// ============ cleanDeptId:正常 + 边界 ============
|
||||
|
||||
@Test
|
||||
void should_remove_square_brackets() {
|
||||
assertEquals("dept-1", FixContactFlowSupport.cleanDeptId("[dept-1]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_remove_brackets_and_trim() {
|
||||
// 多值列表变量场景:整体去括号 + trim
|
||||
assertEquals("dept-1, dept-2", FixContactFlowSupport.cleanDeptId("[dept-1, dept-2]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_keep_plain_id_unchanged() {
|
||||
assertEquals("dept-1", FixContactFlowSupport.cleanDeptId("dept-1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_handle_non_string_object() {
|
||||
// 流程变量可能是任意对象,toString 后处理
|
||||
assertEquals("123", FixContactFlowSupport.cleanDeptId(123L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_null_when_raw_null() {
|
||||
assertNull(FixContactFlowSupport.cleanDeptId(null));
|
||||
}
|
||||
}
|
||||
+603
@@ -0,0 +1,603 @@
|
||||
package org.jeecg.modules.supervision.fixcontact.flow;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.jeecg.common.system.api.ISysBaseAPI;
|
||||
import org.jeecg.modules.supervision.fixcontact.constant.FixContactConstant;
|
||||
import org.jeecg.modules.supervision.fixcontact.entity.FixedContact20260730;
|
||||
import org.jeecg.modules.supervision.fixcontact.entity.FixedContactFeedback20260730;
|
||||
import org.jeecg.modules.supervision.fixcontact.service.IFixedContact20260730Service;
|
||||
import org.jeecg.modules.supervision.fixcontact.service.IFixedContactFeedback20260730Service;
|
||||
import org.jeecg.modules.supervision.xispeak.entity.DeptApproveDetail;
|
||||
import org.jeecg.modules.supervision.xispeak.entity.DeptApproveDetailMap;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* FixContactFlow 流程表达式方法测试(mock 外部依赖:service/iSysBaseAPI/runtimeService)。
|
||||
* 覆盖:业务字段读取、部门角色查询、办结状态、当前部门、反馈、流程变量、JSON 解析、待办人汇总。
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class FixContactFlowTest {
|
||||
|
||||
@Mock private IFixedContact20260730Service fixedContactService;
|
||||
@Mock private IFixedContactFeedback20260730Service feedbackService;
|
||||
@Mock private ISysBaseAPI iSysBaseAPI;
|
||||
@Mock private RuntimeService runtimeService;
|
||||
@Mock private DelegateExecution execution;
|
||||
|
||||
private FixContactFlow flow;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
flow = new FixContactFlow(fixedContactService, feedbackService, null, iSysBaseAPI, runtimeService);
|
||||
}
|
||||
|
||||
/** stub getFixedContact 读取业务表单的公共链路 */
|
||||
private void mockEntity(FixedContact20260730 entity) {
|
||||
when(execution.getVariable(FixContactConstant.FlowVarName.BUSINESS_KEY)).thenReturn("biz-1");
|
||||
when(fixedContactService.getById("biz-1")).thenReturn(entity);
|
||||
}
|
||||
|
||||
// ==================== 业务字段读取 ====================
|
||||
|
||||
@Nested
|
||||
class BusinessFieldRead {
|
||||
|
||||
private FixedContact20260730 fullEntity() {
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setId("biz-1");
|
||||
e.setContactLeader("sld_01");
|
||||
e.setRelatedLeader("sz");
|
||||
e.setApplicant("admin");
|
||||
e.setHostDept("dept-host");
|
||||
e.setCoDept("dept-co");
|
||||
e.setIsNeedAppro("1");
|
||||
e.setSupDeptleaderid("bg_ld_01");
|
||||
e.setContactDept("外单位");
|
||||
return e;
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_contactLeader_when_entity_exists() {
|
||||
mockEntity(fullEntity());
|
||||
assertEquals("sld_01", flow.getContactLeader(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_null_when_entity_not_found() {
|
||||
mockEntity(null);
|
||||
assertNull(flow.getContactLeader(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_relatedLeader() {
|
||||
mockEntity(fullEntity());
|
||||
assertEquals("sz", flow.getRelatedLeader(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_applicant() {
|
||||
mockEntity(fullEntity());
|
||||
assertEquals("admin", flow.getApplicant(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_hostDept() {
|
||||
mockEntity(fullEntity());
|
||||
assertEquals("dept-host", flow.getHostDept(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_coDept() {
|
||||
mockEntity(fullEntity());
|
||||
assertEquals("dept-co", flow.getCoDept(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_isNeedAppro() {
|
||||
mockEntity(fullEntity());
|
||||
assertEquals("1", flow.getIsNeedBgLdApprove(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_supDeptLeaderId() {
|
||||
mockEntity(fullEntity());
|
||||
assertEquals("bg_ld_01", flow.getBgLd(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_contactDept() {
|
||||
mockEntity(fullEntity());
|
||||
assertEquals("外单位", flow.getContactDept(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_null_when_contactLeader_blank() {
|
||||
FixedContact20260730 e = fullEntity();
|
||||
e.setContactLeader(" ");
|
||||
mockEntity(e);
|
||||
assertEquals(" ", flow.getContactLeader(execution));
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 部门+角色查询 ====================
|
||||
|
||||
@Nested
|
||||
class DeptRoleQuery {
|
||||
|
||||
@Test
|
||||
void should_return_office_leader_list() {
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi(
|
||||
FixContactConstant.DeptId.BG_DEPT_ID, FixContactConstant.RoleCode.SLD_ROLE_ID))
|
||||
.thenReturn(List.of("sld_01", "sld_02"));
|
||||
assertEquals(List.of("sld_01", "sld_02"), flow.getOfficeLeaderList(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_office_leader_list_length() {
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi(
|
||||
FixContactConstant.DeptId.BG_DEPT_ID, FixContactConstant.RoleCode.SLD_ROLE_ID))
|
||||
.thenReturn(List.of("sld_01", "sld_02"));
|
||||
assertEquals(2, flow.getOfficeLeaderListLength(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_users_by_dept_and_role() {
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi("dept-100", "ld"))
|
||||
.thenReturn(List.of("u1", "u2"));
|
||||
assertEquals(List.of("u1", "u2"), flow.getUsersByDeptAndRole("dept-100", "ld"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_count_zero_when_no_users() {
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi("dept-100", "ld"))
|
||||
.thenReturn(List.of());
|
||||
assertEquals(0, flow.getUsersByDeptAndRoleCount("dept-100", "ld"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_host_dept_leader_list() {
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setId("biz-1");
|
||||
e.setHostDept("dept-host");
|
||||
mockEntity(e);
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi("dept-host", "ld"))
|
||||
.thenReturn(List.of("leader1", "leader2"));
|
||||
assertEquals(List.of("leader1", "leader2"), flow.getHostDeptLeaderList(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_empty_when_host_dept_has_no_leader() {
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setId("biz-1");
|
||||
e.setHostDept("dept-host");
|
||||
mockEntity(e);
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi("dept-host", "ld"))
|
||||
.thenReturn(List.of());
|
||||
assertEquals(List.of(), flow.getHostDeptLeaderList(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_throw_when_host_dept_blank() {
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setId("biz-1");
|
||||
mockEntity(e);
|
||||
assertThrows(IllegalStateException.class, () -> flow.getHostDeptLeaderList(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_throw_when_entity_not_found_for_host_leader() {
|
||||
mockEntity(null);
|
||||
assertThrows(IllegalStateException.class, () -> flow.getHostDeptLeaderList(execution));
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 办结状态 ====================
|
||||
|
||||
@Nested
|
||||
class IsEndRead {
|
||||
|
||||
@Test
|
||||
void should_return_null_when_dept_id_blank() {
|
||||
// deptId 空白直接短路返回,不触达业务表查询
|
||||
assertNull(flow.getIsEnd(execution, " "));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_null_when_entity_not_found() {
|
||||
mockEntity(null);
|
||||
assertNull(flow.getIsEnd(execution, "dept-1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_null_when_approve_info_empty() {
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setApproveInfo(new DeptApproveDetailMap());
|
||||
mockEntity(e);
|
||||
assertNull(flow.getIsEnd(execution, "dept-1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_isEnd_one_when_finished() {
|
||||
DeptApproveDetail detail = new DeptApproveDetail();
|
||||
detail.setIsEnd(1);
|
||||
DeptApproveDetailMap map = new DeptApproveDetailMap();
|
||||
map.put("dept-1", detail);
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setApproveInfo(map);
|
||||
mockEntity(e);
|
||||
assertEquals("1", flow.getIsEnd(execution, "dept-1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_isEnd_zero_when_unfinished() {
|
||||
DeptApproveDetail detail = new DeptApproveDetail();
|
||||
detail.setIsEnd(0);
|
||||
DeptApproveDetailMap map = new DeptApproveDetailMap();
|
||||
map.put("dept-1", detail);
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setApproveInfo(map);
|
||||
mockEntity(e);
|
||||
assertEquals("0", flow.getIsEnd(execution, "dept-1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_null_when_detail_missing() {
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setApproveInfo(new DeptApproveDetailMap());
|
||||
mockEntity(e);
|
||||
assertNull(flow.getIsEnd(execution, "no-such-dept"));
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 当前部门 ====================
|
||||
|
||||
@Nested
|
||||
class CurrentDept {
|
||||
|
||||
@Test
|
||||
void should_return_null_when_execution_null() {
|
||||
assertNull(flow.getCurrentDeptId(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_clean_local_dept_var() {
|
||||
when(execution.getVariableLocal(FixContactConstant.FlowVarName.IMPL_DEPT_ID)).thenReturn("[dept-1]");
|
||||
assertEquals("dept-1", flow.getCurrentDeptId(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_fallback_to_global_var() {
|
||||
when(execution.getVariableLocal(FixContactConstant.FlowVarName.IMPL_DEPT_ID)).thenReturn(null);
|
||||
when(execution.getVariable(FixContactConstant.FlowVarName.IMPL_DEPT_ID)).thenReturn("dept-2");
|
||||
assertEquals("dept-2", flow.getCurrentDeptId(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_null_when_no_dept_var() {
|
||||
when(execution.getVariableLocal(FixContactConstant.FlowVarName.IMPL_DEPT_ID)).thenReturn(null);
|
||||
when(execution.getVariable(FixContactConstant.FlowVarName.IMPL_DEPT_ID)).thenReturn(null);
|
||||
assertNull(flow.getCurrentDeptId(execution));
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 反馈子表 ====================
|
||||
|
||||
@Nested
|
||||
class Feedback {
|
||||
|
||||
private FixedContactFeedback20260730 feedback(String user, String dept, String finishStatus) {
|
||||
FixedContactFeedback20260730 f = new FixedContactFeedback20260730();
|
||||
f.setFeedbackUser(user);
|
||||
f.setFeedbackDept(dept);
|
||||
f.setFinishStatus(finishStatus);
|
||||
return f;
|
||||
}
|
||||
|
||||
private void mockEntityWithId() {
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setId("biz-1");
|
||||
mockEntity(e);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_empty_when_entity_not_found() {
|
||||
mockEntity(null);
|
||||
assertEquals(List.of(), flow.getFeedbackList(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_feedback_list() {
|
||||
mockEntityWithId();
|
||||
when(feedbackService.selectByMainId("biz-1")).thenReturn(List.of(feedback("u1", "d1", "1")));
|
||||
assertEquals(1, flow.getFeedbackList(execution).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_null_latest_user_when_no_feedback() {
|
||||
mockEntityWithId();
|
||||
when(feedbackService.selectByMainId("biz-1")).thenReturn(List.of());
|
||||
assertNull(flow.getLatestFeedbackUser(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_latest_feedback_user() {
|
||||
mockEntityWithId();
|
||||
when(feedbackService.selectByMainId("biz-1"))
|
||||
.thenReturn(List.of(feedback("u1", "d1", "1"), feedback("u2", "d2", "1")));
|
||||
assertEquals("u2", flow.getLatestFeedbackUser(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_latest_feedback_dept() {
|
||||
mockEntityWithId();
|
||||
when(feedbackService.selectByMainId("biz-1"))
|
||||
.thenReturn(List.of(feedback("u1", "d1", "1"), feedback("u2", "d2", "1")));
|
||||
assertEquals("d2", flow.getLatestFeedbackDept(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_false_when_no_feedback() {
|
||||
mockEntityWithId();
|
||||
when(feedbackService.selectByMainId("biz-1")).thenReturn(List.of());
|
||||
assertFalse(flow.isAllFeedbackFinished(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_true_when_all_finished() {
|
||||
mockEntityWithId();
|
||||
when(feedbackService.selectByMainId("biz-1"))
|
||||
.thenReturn(List.of(feedback("u1", "d1", "1"), feedback("u2", "d2", "1")));
|
||||
assertTrue(flow.isAllFeedbackFinished(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_false_when_any_feedback_unfinished() {
|
||||
mockEntityWithId();
|
||||
when(feedbackService.selectByMainId("biz-1"))
|
||||
.thenReturn(List.of(feedback("u1", "d1", "1"), feedback("u2", "d2", " ")));
|
||||
assertFalse(flow.isAllFeedbackFinished(execution));
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 流程变量 ====================
|
||||
|
||||
@Nested
|
||||
class ProcessVariable {
|
||||
|
||||
@Test
|
||||
void should_return_var_value() {
|
||||
when(execution.getProcessInstanceId()).thenReturn("proc-1");
|
||||
when(runtimeService.getVariable("proc-1", "name")).thenReturn("val");
|
||||
assertEquals("val", flow.getVar(execution, "name"));
|
||||
org.mockito.Mockito.verify(execution).getProcessInstanceId();
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_null_when_var_absent() {
|
||||
when(execution.getProcessInstanceId()).thenReturn("proc-1");
|
||||
when(runtimeService.getVariable("proc-1", "name")).thenReturn(null);
|
||||
assertNull(flow.getVar(execution, "name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_default_zero_when_need_leader_approve_blank() {
|
||||
when(execution.getProcessInstanceId()).thenReturn("proc-1");
|
||||
when(runtimeService.getVariable("proc-1", FixContactConstant.FlowVarName.IS_NEED_LEADER_APPROVE))
|
||||
.thenReturn(null);
|
||||
assertEquals("0", flow.getIsNeedLeaderApprove(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_need_leader_approve_value() {
|
||||
when(execution.getProcessInstanceId()).thenReturn("proc-1");
|
||||
when(runtimeService.getVariable("proc-1", FixContactConstant.FlowVarName.IS_NEED_LEADER_APPROVE))
|
||||
.thenReturn("1");
|
||||
assertEquals("1", flow.getIsNeedLeaderApprove(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_split_var_as_list() {
|
||||
when(execution.getProcessInstanceId()).thenReturn("proc-1");
|
||||
when(runtimeService.getVariable("proc-1", FixContactConstant.FlowVarName.LEADER_APPROVE_USER))
|
||||
.thenReturn("sld_01, sld_02");
|
||||
assertEquals(List.of("sld_01", "sld_02"), flow.getLeaderApproveUserList(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_empty_list_when_var_null() {
|
||||
when(execution.getProcessInstanceId()).thenReturn("proc-1");
|
||||
when(runtimeService.getVariable("proc-1", FixContactConstant.FlowVarName.LEADER_APPROVE_USER))
|
||||
.thenReturn(null);
|
||||
assertEquals(List.of(), flow.getLeaderApproveUserList(execution));
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== JSON 解析 ====================
|
||||
|
||||
@Nested
|
||||
class JsonParse {
|
||||
|
||||
@Test
|
||||
void should_parse_from_json_object() {
|
||||
JSONObject data = new JSONObject().fluentPut("contactLeader", "sld_01");
|
||||
assertEquals("sld_01", flow.getContactLeaderFromJson(data));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_parse_from_json_string() {
|
||||
assertEquals("sld_01", flow.getContactLeaderFromJson("{\"contactLeader\":\"sld_01\"}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_null_when_json_null() {
|
||||
assertNull(flow.getContactLeaderFromJson(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_null_when_invalid_json() {
|
||||
assertNull(flow.getContactLeaderFromJson("not-a-json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_host_dept_leader_list_from_json() {
|
||||
when(iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi("dept-host", "ld"))
|
||||
.thenReturn(List.of("leader1"));
|
||||
assertEquals(List.of("leader1"), flow.getHostDeptLeaderListFromJson(
|
||||
new JSONObject().fluentPut("hostDept", "dept-host")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_empty_when_host_dept_blank_in_json() {
|
||||
assertEquals(List.of(), flow.getHostDeptLeaderListFromJson(
|
||||
new JSONObject().fluentPut("hostDept", " ")));
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 部门列表组装 ====================
|
||||
|
||||
@Nested
|
||||
class DeptIdList {
|
||||
|
||||
@Test
|
||||
void should_compose_host_and_co_dept() {
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setId("biz-1");
|
||||
e.setHostDept("dept-host");
|
||||
e.setCoDept("dept-co");
|
||||
mockEntity(e);
|
||||
assertEquals(List.of("dept-host", "dept-co"), flow.getDeptIdList(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_compose_only_host_dept() {
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setId("biz-1");
|
||||
e.setHostDept("dept-host");
|
||||
mockEntity(e);
|
||||
assertEquals(List.of("dept-host"), flow.getDeptIdList(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_empty_when_entity_not_found() {
|
||||
mockEntity(null);
|
||||
assertEquals(List.of(), flow.getDeptIdList(execution));
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 待办人汇总 ====================
|
||||
|
||||
@Nested
|
||||
class TodoUser {
|
||||
|
||||
private FixedContact20260730 entityWithApproveInfo() {
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setId("biz-1");
|
||||
e.setHostDept("dept-host");
|
||||
e.setCoDept("dept-co");
|
||||
mockEntity(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_empty_when_approve_info_empty() {
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setId("biz-1");
|
||||
e.setHostDept("dept-host");
|
||||
e.setCoDept("dept-co");
|
||||
e.setApproveInfo(new DeptApproveDetailMap());
|
||||
mockEntity(e);
|
||||
assertEquals(List.of(), flow.getTodoUserList(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_use_impl_user_name_list_when_not_finished() {
|
||||
// isEnd=0:多选经办人 implUserNameList
|
||||
DeptApproveDetail detail = new DeptApproveDetail();
|
||||
detail.setIsEnd(0);
|
||||
detail.setImplUserNameList(List.of("worker1", "worker2"));
|
||||
DeptApproveDetailMap map = new DeptApproveDetailMap();
|
||||
map.put("dept-host", detail);
|
||||
entityWithApproveInfo().setApproveInfo(map);
|
||||
assertEquals(List.of("worker1", "worker2"), flow.getTodoUserList(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_use_impl_worker_when_finished() {
|
||||
// isEnd=1:单选经办人 implWorker
|
||||
DeptApproveDetail detail = new DeptApproveDetail();
|
||||
detail.setIsEnd(1);
|
||||
detail.setImplWorker("worker1");
|
||||
DeptApproveDetailMap map = new DeptApproveDetailMap();
|
||||
map.put("dept-host", detail);
|
||||
entityWithApproveInfo().setApproveInfo(map);
|
||||
assertEquals(List.of("worker1"), flow.getTodoUserList(execution));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_deduplicate_users_across_depts() {
|
||||
// 两部门分配同一经办人:LinkedHashSet 去重保序
|
||||
DeptApproveDetail d1 = new DeptApproveDetail();
|
||||
d1.setIsEnd(0);
|
||||
d1.setImplUserNameList(List.of("shared"));
|
||||
DeptApproveDetail d2 = new DeptApproveDetail();
|
||||
d2.setIsEnd(0);
|
||||
d2.setImplUserNameList(List.of("shared", "worker2"));
|
||||
DeptApproveDetailMap map = new DeptApproveDetailMap();
|
||||
map.put("dept-host", d1);
|
||||
map.put("dept-co", d2);
|
||||
entityWithApproveInfo().setApproveInfo(map);
|
||||
assertEquals(List.of("shared", "worker2"), flow.getTodoUserList(execution));
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 当前部门经办人 ====================
|
||||
|
||||
@Nested
|
||||
class CurrentDeptWorker {
|
||||
|
||||
@Test
|
||||
void should_return_empty_when_detail_null() {
|
||||
assertEquals(List.of(), flow.getCurrentDeptWorkerList(execution, "dept-1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_impl_user_name_list() {
|
||||
DeptApproveDetail detail = new DeptApproveDetail();
|
||||
detail.setImplUserNameList(List.of("w1", "w2"));
|
||||
when(execution.getVariable(FixContactConstant.FlowVarName.BUSINESS_KEY)).thenReturn("biz-1");
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setApproveInfo(new DeptApproveDetailMap());
|
||||
e.getApproveInfo().put("dept-1", detail);
|
||||
when(fixedContactService.getById("biz-1")).thenReturn(e);
|
||||
assertEquals(List.of("w1", "w2"), flow.getCurrentDeptWorkerList(execution, "dept-1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_singleton_impl_worker() {
|
||||
DeptApproveDetail detail = new DeptApproveDetail();
|
||||
detail.setImplWorker("w1");
|
||||
when(execution.getVariable(FixContactConstant.FlowVarName.BUSINESS_KEY)).thenReturn("biz-1");
|
||||
FixedContact20260730 e = new FixedContact20260730();
|
||||
e.setApproveInfo(new DeptApproveDetailMap());
|
||||
e.getApproveInfo().put("dept-1", detail);
|
||||
when(fixedContactService.getById("biz-1")).thenReturn(e);
|
||||
assertEquals(List.of("w1"), flow.getCurrentDeptWorkerList(execution, "dept-1"));
|
||||
}
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package org.jeecg.modules.supervision.fixcontact.listener;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.NullAndEmptySource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
/**
|
||||
* FixContactApprovalHelper.resolveTargetExecutionId 规则测试(TDD 红-绿-重构 演示)。
|
||||
*
|
||||
* 业务规则(来自 FixContactDeptLeaderApproveListener 第 53-69 行):
|
||||
* 部门领导审批后,领导变量要写入"上两级"执行实例:
|
||||
* - 存在第二层父级(大会签容器/外层作用域)→ 写入第二层 grandParentId
|
||||
* - 不存在第二层父级 → 写入第一层 parentId
|
||||
* - 第一层 parentId 为空 → 无目标,返回 null(调用方跳过写入)
|
||||
*/
|
||||
class FixContactApprovalHelperTest {
|
||||
|
||||
// ============ 正常路径 ============
|
||||
|
||||
@Test
|
||||
void should_return_grandParent_when_both_levels_exist() {
|
||||
// 两级父级都存在(子流程内会签容器场景)
|
||||
String target = FixContactApprovalHelper.resolveTargetExecutionId("parent-1", "grand-1");
|
||||
assertEquals("grand-1", target);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_parent_when_no_grand_parent() {
|
||||
// 只有第一层父级(无外层容器)
|
||||
String target = FixContactApprovalHelper.resolveTargetExecutionId("parent-1", null);
|
||||
assertEquals("parent-1", target);
|
||||
}
|
||||
|
||||
// ============ 边界路径 ============
|
||||
|
||||
@ParameterizedTest
|
||||
@NullAndEmptySource
|
||||
@ValueSource(strings = {" ", " "})
|
||||
void should_return_parent_when_grand_parent_blank(String grandParentId) {
|
||||
// 第二层为空串/空白串:视为不存在,退回第一层(原逻辑 isNotBlank 判定)
|
||||
String target = FixContactApprovalHelper.resolveTargetExecutionId("parent-1", grandParentId);
|
||||
assertEquals("parent-1", target);
|
||||
}
|
||||
|
||||
// ============ 异常路径 ============
|
||||
|
||||
@ParameterizedTest
|
||||
@NullAndEmptySource
|
||||
@ValueSource(strings = {" ", " "})
|
||||
void should_return_null_when_parent_blank(String parentId) {
|
||||
// 第一层父级都没有:无目标执行实例,返回 null 供调用方跳过
|
||||
assertNull(FixContactApprovalHelper.resolveTargetExecutionId(parentId, "grand-1"));
|
||||
}
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
package org.jeecg.modules.supervision.fixcontact.listener;
|
||||
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.runtime.Execution;
|
||||
import org.flowable.engine.runtime.ExecutionQuery;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
import org.jeecg.modules.supervision.fixcontact.constant.FixContactConstant;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* FixContactDeptLeaderApproveListener 部门领导审批监听器测试(重构依赖注入后可测)。
|
||||
* 规则:将 assignee 写入"上两级"执行实例局部变量——有第二层父级存第二层,否则存第一层。
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class FixContactDeptLeaderApproveListenerTest {
|
||||
|
||||
@Mock private RuntimeService runtimeService;
|
||||
@Mock private DelegateTask delegateTask;
|
||||
@Mock private Execution currentExecution;
|
||||
@Mock private Execution parentExecution;
|
||||
@Mock private ExecutionQuery query;
|
||||
@Mock private ExecutionQuery parentQuery;
|
||||
|
||||
private FixContactDeptLeaderApproveListener listener;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
listener = new FixContactDeptLeaderApproveListener(runtimeService);
|
||||
}
|
||||
|
||||
/** 链式 stub:第一次 createExecutionQuery 查当前执行,第二次查父级执行 */
|
||||
private void mockExecutionChain(String parentId, String grandParentId) {
|
||||
when(delegateTask.getAssignee()).thenReturn("leader1");
|
||||
when(delegateTask.getExecutionId()).thenReturn("exec-1");
|
||||
when(runtimeService.createExecutionQuery()).thenReturn(query, parentQuery);
|
||||
when(query.executionId("exec-1")).thenReturn(query);
|
||||
when(query.singleResult()).thenReturn(currentExecution);
|
||||
when(currentExecution.getParentId()).thenReturn(parentId);
|
||||
when(parentQuery.executionId(parentId)).thenReturn(parentQuery);
|
||||
when(parentQuery.singleResult()).thenReturn(parentExecution);
|
||||
when(parentExecution.getParentId()).thenReturn(grandParentId);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_when_task_null() {
|
||||
listener.notify(null);
|
||||
verify(runtimeService, never()).setVariableLocal(any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_skip_when_assignee_blank() {
|
||||
when(delegateTask.getAssignee()).thenReturn(" ");
|
||||
listener.notify(delegateTask);
|
||||
verify(runtimeService, never()).setVariableLocal(any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_skip_when_execution_id_blank() {
|
||||
when(delegateTask.getAssignee()).thenReturn("leader1");
|
||||
when(delegateTask.getExecutionId()).thenReturn("");
|
||||
listener.notify(delegateTask);
|
||||
verify(runtimeService, never()).setVariableLocal(any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_skip_when_current_execution_not_found() {
|
||||
when(delegateTask.getAssignee()).thenReturn("leader1");
|
||||
when(delegateTask.getExecutionId()).thenReturn("exec-1");
|
||||
when(runtimeService.createExecutionQuery()).thenReturn(query);
|
||||
when(query.executionId("exec-1")).thenReturn(query);
|
||||
when(query.singleResult()).thenReturn(null);
|
||||
listener.notify(delegateTask);
|
||||
verify(runtimeService, never()).setVariableLocal(any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_skip_when_parent_id_blank() {
|
||||
when(delegateTask.getAssignee()).thenReturn("leader1");
|
||||
when(delegateTask.getExecutionId()).thenReturn("exec-1");
|
||||
when(runtimeService.createExecutionQuery()).thenReturn(query);
|
||||
when(query.executionId("exec-1")).thenReturn(query);
|
||||
when(query.singleResult()).thenReturn(currentExecution);
|
||||
when(currentExecution.getParentId()).thenReturn(" ");
|
||||
listener.notify(delegateTask);
|
||||
verify(runtimeService, never()).setVariableLocal(any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_skip_when_parent_execution_not_found() {
|
||||
// 单独 stub(不复用 mockExecutionChain,避免无用 stub)
|
||||
when(delegateTask.getAssignee()).thenReturn("leader1");
|
||||
when(delegateTask.getExecutionId()).thenReturn("exec-1");
|
||||
when(runtimeService.createExecutionQuery()).thenReturn(query, parentQuery);
|
||||
when(query.executionId("exec-1")).thenReturn(query);
|
||||
when(query.singleResult()).thenReturn(currentExecution);
|
||||
when(currentExecution.getParentId()).thenReturn("parent-1");
|
||||
when(parentQuery.executionId("parent-1")).thenReturn(parentQuery);
|
||||
when(parentQuery.singleResult()).thenReturn(null);
|
||||
listener.notify(delegateTask);
|
||||
verify(runtimeService, never()).setVariableLocal(any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_write_to_grand_parent_when_both_levels_exist() {
|
||||
mockExecutionChain("parent-1", "grand-1");
|
||||
listener.notify(delegateTask);
|
||||
verify(runtimeService).setVariableLocal("grand-1", FixContactConstant.FlowVarName.TEM_IMPL_LEADER, "leader1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_write_to_parent_when_no_grand_parent() {
|
||||
mockExecutionChain("parent-1", null);
|
||||
listener.notify(delegateTask);
|
||||
verify(runtimeService).setVariableLocal("parent-1", FixContactConstant.FlowVarName.TEM_IMPL_LEADER, "leader1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_not_throw_when_set_variable_fails() {
|
||||
mockExecutionChain("parent-1", "grand-1");
|
||||
doThrow(new RuntimeException("boom")).when(runtimeService).setVariableLocal("grand-1", FixContactConstant.FlowVarName.TEM_IMPL_LEADER, "leader1");
|
||||
// 不抛异常即通过(异常被 catch)
|
||||
listener.notify(delegateTask);
|
||||
}
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
package org.jeecg.modules.supervision.fixcontact.listener;
|
||||
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
import org.jeecg.modules.supervision.fixcontact.constant.FixContactConstant;
|
||||
import org.jeecg.modules.supervision.fixcontact.entity.FixedContact20260730;
|
||||
import org.jeecg.modules.supervision.fixcontact.service.IFixedContact20260730Service;
|
||||
import org.jeecg.modules.supervision.xispeak.entity.DeptApproveDetail;
|
||||
import org.jeecg.modules.supervision.xispeak.entity.DeptApproveDetailMap;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* FixContactWorkerApproveListener 经办人会签监听器测试。
|
||||
* 规则:写入子流程局部变量 tem_impl_worker + 记录经办人到 approveInfo 对应部门(去重)。
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class FixContactWorkerApproveListenerTest {
|
||||
|
||||
@Mock private IFixedContact20260730Service fixedContactService;
|
||||
@Mock private RuntimeService runtimeService;
|
||||
@Mock private DelegateTask delegateTask;
|
||||
|
||||
private FixContactWorkerApproveListener listener;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
listener = new FixContactWorkerApproveListener(fixedContactService, runtimeService);
|
||||
}
|
||||
|
||||
/** 正常办理链路:assignee + executionId + businessKey + deptVar 齐备 */
|
||||
private void mockNormalTask(String deptVar) {
|
||||
when(delegateTask.getAssignee()).thenReturn("worker1");
|
||||
when(delegateTask.getExecutionId()).thenReturn("exec-1");
|
||||
when(delegateTask.getVariable(FixContactConstant.FlowVarName.BUSINESS_KEY)).thenReturn("biz-1");
|
||||
when(delegateTask.getVariableLocal(FixContactConstant.FlowVarName.IMPL_DEPT_ID)).thenReturn(deptVar);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_when_task_null() {
|
||||
listener.notify(null);
|
||||
verify(runtimeService, never()).setVariableLocal(org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_skip_when_assignee_blank() {
|
||||
when(delegateTask.getAssignee()).thenReturn(" ");
|
||||
listener.notify(delegateTask);
|
||||
verify(runtimeService, never()).setVariableLocal(org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any());
|
||||
verify(fixedContactService, never()).updateById(org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_write_worker_local_var() {
|
||||
mockNormalTask("dept-1");
|
||||
FixedContact20260730 entity = new FixedContact20260730();
|
||||
entity.setId("biz-1");
|
||||
entity.setApproveInfo(new DeptApproveDetailMap());
|
||||
when(fixedContactService.getByIdForUpdate("biz-1")).thenReturn(entity);
|
||||
|
||||
listener.notify(delegateTask);
|
||||
|
||||
verify(runtimeService).setVariableLocal("exec-1", FixContactConstant.FlowVarName.TEM_IMPL_WORKER, "worker1");
|
||||
verify(fixedContactService).updateById(entity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_skip_record_when_business_key_missing() {
|
||||
when(delegateTask.getAssignee()).thenReturn("worker1");
|
||||
when(delegateTask.getExecutionId()).thenReturn("exec-1");
|
||||
when(delegateTask.getVariable(FixContactConstant.FlowVarName.BUSINESS_KEY)).thenReturn(null);
|
||||
|
||||
listener.notify(delegateTask);
|
||||
|
||||
verify(fixedContactService, never()).updateById(org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_skip_record_when_dept_var_missing() {
|
||||
when(delegateTask.getAssignee()).thenReturn("worker1");
|
||||
when(delegateTask.getExecutionId()).thenReturn("exec-1");
|
||||
when(delegateTask.getVariable(FixContactConstant.FlowVarName.BUSINESS_KEY)).thenReturn("biz-1");
|
||||
when(delegateTask.getVariableLocal(FixContactConstant.FlowVarName.IMPL_DEPT_ID)).thenReturn(null);
|
||||
when(delegateTask.getVariable(FixContactConstant.FlowVarName.IMPL_DEPT_ID)).thenReturn(null);
|
||||
|
||||
listener.notify(delegateTask);
|
||||
|
||||
verify(fixedContactService, never()).updateById(org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_skip_record_when_entity_not_found() {
|
||||
mockNormalTask("dept-1");
|
||||
when(fixedContactService.getByIdForUpdate("biz-1")).thenReturn(null);
|
||||
|
||||
listener.notify(delegateTask);
|
||||
|
||||
verify(fixedContactService, never()).updateById(org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_append_worker_to_existing_detail() {
|
||||
mockNormalTask("dept-1");
|
||||
DeptApproveDetail detail = new DeptApproveDetail();
|
||||
detail.setDeptId("dept-1");
|
||||
detail.setImplUserNameList(new ArrayList<>(List.of("old_worker")));
|
||||
DeptApproveDetailMap map = new DeptApproveDetailMap();
|
||||
map.put("dept-1", detail);
|
||||
FixedContact20260730 entity = new FixedContact20260730();
|
||||
entity.setId("biz-1");
|
||||
entity.setApproveInfo(map);
|
||||
when(fixedContactService.getByIdForUpdate("biz-1")).thenReturn(entity);
|
||||
|
||||
listener.notify(delegateTask);
|
||||
|
||||
assertEquals(List.of("old_worker", "worker1"), detail.getImplUserNameList());
|
||||
verify(fixedContactService).updateById(entity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_create_detail_when_dept_not_in_map() {
|
||||
// approveInfo 为 null + dept 无 detail:新建 map + detail
|
||||
mockNormalTask("dept-1");
|
||||
FixedContact20260730 entity = new FixedContact20260730();
|
||||
entity.setId("biz-1");
|
||||
when(fixedContactService.getByIdForUpdate("biz-1")).thenReturn(entity);
|
||||
|
||||
listener.notify(delegateTask);
|
||||
|
||||
assertEquals(List.of("worker1"), entity.getApproveInfo().get("dept-1").getImplUserNameList());
|
||||
verify(fixedContactService).updateById(entity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_not_update_when_worker_already_in_list() {
|
||||
mockNormalTask("dept-1");
|
||||
DeptApproveDetail detail = new DeptApproveDetail();
|
||||
detail.setDeptId("dept-1");
|
||||
detail.setImplUserNameList(new ArrayList<>(List.of("worker1")));
|
||||
DeptApproveDetailMap map = new DeptApproveDetailMap();
|
||||
map.put("dept-1", detail);
|
||||
FixedContact20260730 entity = new FixedContact20260730();
|
||||
entity.setId("biz-1");
|
||||
entity.setApproveInfo(map);
|
||||
when(fixedContactService.getByIdForUpdate("biz-1")).thenReturn(entity);
|
||||
|
||||
listener.notify(delegateTask);
|
||||
|
||||
assertEquals(1, detail.getImplUserNameList().size());
|
||||
verify(fixedContactService, never()).updateById(org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_clean_dept_var_with_brackets() {
|
||||
// 部门变量带 []:记录到清洗后的 dept key
|
||||
mockNormalTask("[dept-1]");
|
||||
FixedContact20260730 entity = new FixedContact20260730();
|
||||
entity.setId("biz-1");
|
||||
entity.setApproveInfo(new DeptApproveDetailMap());
|
||||
when(fixedContactService.getByIdForUpdate("biz-1")).thenReturn(entity);
|
||||
|
||||
listener.notify(delegateTask);
|
||||
|
||||
assertTrue(entity.getApproveInfo().containsKey("dept-1"));
|
||||
assertEquals("dept-1", entity.getApproveInfo().get("dept-1").getDeptId());
|
||||
}
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
package org.jeecg.modules.supervision.fixcontact.service.impl;
|
||||
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.jeecg.common.exception.JeecgBootException;
|
||||
import org.jeecg.modules.supervision.fixcontact.entity.FixedContact20260730;
|
||||
import org.jeecg.modules.supervision.fixcontact.entity.FixedContactFeedback20260730;
|
||||
import org.jeecg.modules.supervision.fixcontact.mapper.FixedContact20260730Mapper;
|
||||
import org.jeecg.modules.supervision.fixcontact.mapper.FixedContactFeedback20260730Mapper;
|
||||
import org.jeecg.modules.supervision.xispeak.entity.DeptApproveDetail;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* FixedContact20260730ServiceImpl 测试(mock mapper + runtimeService)。
|
||||
* 核心:saveSubApprove 部门审批保存规则(isEnd=1 存 implWorker / isEnd=0 存 implUserNameList)+ 主从 CRUD。
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class FixedContact20260730ServiceImplTest {
|
||||
|
||||
@Mock private FixedContact20260730Mapper baseMapper;
|
||||
@Mock private FixedContactFeedback20260730Mapper feedbackMapper;
|
||||
@Mock private RuntimeService runtimeService;
|
||||
|
||||
private FixedContact20260730ServiceImpl service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new FixedContact20260730ServiceImpl();
|
||||
ReflectionTestUtils.setField(service, "baseMapper", baseMapper);
|
||||
ReflectionTestUtils.setField(service, "fixedContactFeedback20260730Mapper", feedbackMapper);
|
||||
ReflectionTestUtils.setField(service, "runtimeService", runtimeService);
|
||||
}
|
||||
|
||||
// ==================== saveSubApprove(核心业务规则) ====================
|
||||
|
||||
@Test
|
||||
void should_throw_when_main_not_exists() {
|
||||
when(baseMapper.selectOne(any(), anyBoolean())).thenReturn(null);
|
||||
assertThrows(JeecgBootException.class, () -> service.saveSubApprove("no-such", "dept-1", 1, "w1", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_store_impl_worker_when_is_end_one() {
|
||||
// isEnd=1(办结):单选经办人 implWorker,清空 implUserNameList
|
||||
FixedContact20260730 entity = new FixedContact20260730();
|
||||
entity.setId("biz-1");
|
||||
when(baseMapper.selectOne(any(), anyBoolean())).thenReturn(entity);
|
||||
|
||||
service.saveSubApprove("biz-1", "dept-1", 1, "w1", List.of("w2"));
|
||||
|
||||
DeptApproveDetail detail = entity.getApproveInfo().get("dept-1");
|
||||
assertEquals("w1", detail.getImplWorker());
|
||||
assertNull(detail.getImplUserNameList());
|
||||
verify(baseMapper).updateById(entity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_store_impl_user_name_list_when_is_end_zero() {
|
||||
// isEnd=0(分配经办人):多选 implUserNameList,清空 implWorker
|
||||
FixedContact20260730 entity = new FixedContact20260730();
|
||||
entity.setId("biz-1");
|
||||
when(baseMapper.selectOne(any(), anyBoolean())).thenReturn(entity);
|
||||
|
||||
service.saveSubApprove("biz-1", "dept-1", 0, "w1", List.of("w2", "w3"));
|
||||
|
||||
DeptApproveDetail detail = entity.getApproveInfo().get("dept-1");
|
||||
assertNull(detail.getImplWorker());
|
||||
assertEquals(List.of("w2", "w3"), detail.getImplUserNameList());
|
||||
verify(baseMapper).updateById(entity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_merge_into_existing_detail() {
|
||||
// 同一部门二次保存:覆盖原有 detail 而不重建
|
||||
FixedContact20260730 entity = new FixedContact20260730();
|
||||
entity.setId("biz-1");
|
||||
entity.setApproveInfo(new org.jeecg.modules.supervision.xispeak.entity.DeptApproveDetailMap());
|
||||
DeptApproveDetail existing = new DeptApproveDetail();
|
||||
existing.setDeptId("dept-1");
|
||||
entity.getApproveInfo().put("dept-1", existing);
|
||||
when(baseMapper.selectOne(any(), anyBoolean())).thenReturn(entity);
|
||||
|
||||
service.saveSubApprove("biz-1", "dept-1", 0, null, List.of("w9"));
|
||||
|
||||
DeptApproveDetail detail = entity.getApproveInfo().get("dept-1");
|
||||
assertEquals(List.of("w9"), detail.getImplUserNameList());
|
||||
verify(baseMapper).updateById(entity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_create_map_when_approve_info_null() {
|
||||
FixedContact20260730 entity = new FixedContact20260730();
|
||||
entity.setId("biz-1");
|
||||
when(baseMapper.selectOne(any(), anyBoolean())).thenReturn(entity);
|
||||
|
||||
service.saveSubApprove("biz-1", "dept-9", 0, null, List.of("w1"));
|
||||
|
||||
assertEquals(List.of("w1"), entity.getApproveInfo().get("dept-9").getImplUserNameList());
|
||||
}
|
||||
|
||||
// ==================== 主从 CRUD ====================
|
||||
|
||||
@Test
|
||||
void should_save_main_and_sub_list() {
|
||||
FixedContact20260730 main = new FixedContact20260730();
|
||||
main.setId("biz-1");
|
||||
FixedContactFeedback20260730 sub = new FixedContactFeedback20260730();
|
||||
|
||||
service.saveMain(main, List.of(sub));
|
||||
|
||||
verify(baseMapper).insert(main);
|
||||
assertEquals("biz-1", sub.getFixedContact20260730Id());
|
||||
verify(feedbackMapper).insert(sub);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_save_main_without_sub_when_list_null() {
|
||||
FixedContact20260730 main = new FixedContact20260730();
|
||||
service.saveMain(main, null);
|
||||
verify(baseMapper).insert(main);
|
||||
verify(feedbackMapper, never()).insert(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_update_main_and_replace_sub() {
|
||||
FixedContact20260730 main = new FixedContact20260730();
|
||||
main.setId("biz-1");
|
||||
FixedContactFeedback20260730 sub = new FixedContactFeedback20260730();
|
||||
|
||||
service.updateMain(main, List.of(sub));
|
||||
|
||||
verify(baseMapper).updateById(main);
|
||||
verify(feedbackMapper).deleteByMainId("biz-1");
|
||||
assertEquals("biz-1", sub.getFixedContact20260730Id());
|
||||
verify(feedbackMapper).insert(sub);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_delete_main_with_sub() {
|
||||
service.delMain("biz-1");
|
||||
verify(feedbackMapper).deleteByMainId("biz-1");
|
||||
verify(baseMapper).deleteById("biz-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_delete_batch_with_sub() {
|
||||
service.delBatchMain(List.of("biz-1", "biz-2"));
|
||||
verify(feedbackMapper).deleteByMainId("biz-1");
|
||||
verify(baseMapper).deleteById("biz-1");
|
||||
verify(feedbackMapper).deleteByMainId("biz-2");
|
||||
verify(baseMapper).deleteById("biz-2");
|
||||
}
|
||||
|
||||
// ==================== 流程变量同步 ====================
|
||||
|
||||
@Test
|
||||
void should_update_form_and_sync_variable() {
|
||||
FixedContact20260730 form = new FixedContact20260730();
|
||||
service.saveBpmFormAndSyncVariable(form, "proc-1", "json_data", "{\"a\":1}");
|
||||
verify(baseMapper).updateById(form);
|
||||
verify(runtimeService).setVariable("proc-1", "json_data", "{\"a\":1}");
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,11 @@
|
||||
<artifactId>jeecg-system-cloud-api</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!-- 基础核心(代码直接使用 base-core 的 Result/LoginUser/LowAppCopyMenu 等) -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-base-core</artifactId>
|
||||
</dependency>
|
||||
<!-- feign -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<properties>
|
||||
<jeecgboot.version>3.8.0</jeecgboot.version>
|
||||
<!-- 默认跳过单测,需显式 -DskipTests=false 开启(回归测试等场景) -->
|
||||
<skipTests>true</skipTests>
|
||||
<skipTests>false</skipTests>
|
||||
<!-- JDK版本支持17和1.8 -->
|
||||
<java.version>17</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
@@ -556,6 +556,27 @@
|
||||
<skipTests>${skipTests}</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- JaCoCo 代码覆盖率:prepare-agent 给测试 JVM 插桩,report 在 test 阶段生成 target/site/jacoco 报告 -->
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.12</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>jacoco-prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>jacoco-report</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- 避免font文件的二进制文件格式压缩破坏 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
||||
Reference in New Issue
Block a user