Prechádzať zdrojové kódy

test(task-plan): 统一任务生成器幂等/生成/级联清理单元测试

iwt 2 týždňov pred
rodič
commit
ddf650e0bb

+ 113 - 0
cfc-backend/src/test/java/com/etotem/cfc/unit/TaskPlanServiceTest.java

@@ -0,0 +1,113 @@
+package com.etotem.cfc.unit;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.etotem.cfc.entity.Task;
+import com.etotem.cfc.entity.TaskPlanInstance;
+import com.etotem.cfc.entity.TaskTemplateItem;
+import com.etotem.cfc.mapper.TaskMapper;
+import com.etotem.cfc.mapper.TaskPlanInstanceMapper;
+import com.etotem.cfc.mapper.TaskPlanItemMapper;
+import com.etotem.cfc.mapper.TaskTemplateItemMapper;
+import com.etotem.cfc.service.TaskPlanService;
+import com.etotem.cfc.service.TaskTemplatePackageService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.*;
+
+/**
+ * 统一任务生成器单元测试(纯逻辑,mock Mapper,无需 DB)
+ */
+class TaskPlanServiceTest {
+
+    private TaskPlanService service;
+    private TaskMapper taskMapper;
+    private TaskPlanInstanceMapper instanceMapper;
+    private TaskPlanItemMapper planItemMapper;
+    private TaskTemplateItemMapper templateItemMapper;
+    private TaskTemplatePackageService packageService;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        service = new TaskPlanService();
+        taskMapper = mock(TaskMapper.class);
+        instanceMapper = mock(TaskPlanInstanceMapper.class);
+        planItemMapper = mock(TaskPlanItemMapper.class);
+        templateItemMapper = mock(TaskTemplateItemMapper.class);
+        packageService = mock(TaskTemplatePackageService.class);
+        inject("taskMapper", taskMapper);
+        inject("instanceMapper", instanceMapper);
+        inject("planItemMapper", planItemMapper);
+        inject("templateItemMapper", templateItemMapper);
+        inject("packageService", packageService);
+    }
+
+    private void inject(String field, Object value) throws Exception {
+        Field f = TaskPlanService.class.getDeclaredField(field);
+        f.setAccessible(true);
+        f.set(service, value);
+    }
+
+    @Test
+    void generateTasksFromTemplate_已生成过则跳过() {
+        TaskPlanInstance plan = new TaskPlanInstance();
+        plan.setId(1L);
+        plan.setFamilyId(10L);
+        plan.setChildId(20L);
+        plan.setName("测试方案");
+        when(taskMapper.selectCount(any(LambdaQueryWrapper.class))).thenReturn(5L);
+
+        int count = service.generateTasksFromTemplate(plan, 99L);
+
+        assertEquals(0, count);
+        verify(taskMapper, never()).insert(any(Task.class));
+    }
+
+    @Test
+    void generateTasksFromTemplate_生成引导任务和模板任务() {
+        TaskPlanInstance plan = new TaskPlanInstance();
+        plan.setId(1L);
+        plan.setFamilyId(10L);
+        plan.setChildId(20L);
+        plan.setName("测试方案");
+        plan.setPackageId(30L);
+        when(taskMapper.selectCount(any(LambdaQueryWrapper.class))).thenReturn(0L);
+
+        TaskTemplateItem item = new TaskTemplateItem();
+        item.setTaskName("每日运动");
+        item.setPoints(5);
+        item.setFrequency("daily");
+        when(templateItemMapper.selectList(any(com.baomidou.mybatisplus.core.conditions.query.QueryWrapper.class)))
+                .thenReturn(Collections.singletonList(item));
+
+        int count = service.generateTasksFromTemplate(plan, 99L);
+
+        // 引导任务 + 1 模板任务
+        assertEquals(2, count);
+        verify(taskMapper, times(2)).insert(any(Task.class));
+    }
+
+    @Test
+    void cancelPlan_级联清理未完成任务() {
+        TaskPlanInstance plan = new TaskPlanInstance();
+        plan.setId(1L);
+        plan.setFamilyId(10L);
+        plan.setChildId(20L);
+        plan.setStatus("active");
+        when(instanceMapper.selectById(1L)).thenReturn(plan);
+        when(instanceMapper.updateById(any(TaskPlanInstance.class))).thenReturn(1);
+        when(taskMapper.selectList(any(LambdaQueryWrapper.class)))
+                .thenReturn(Collections.singletonList(new Task()));
+
+        boolean ok = service.cancelPlan(1L);
+
+        assertEquals(true, ok);
+        verify(taskMapper, times(1)).updateById(any(Task.class));
+    }
+}