Просмотр исходного кода

chore: auto bump version and changelog [skip ci]

iwt 2 месяцев назад
Родитель
Сommit
f0641c8a35
23 измененных файлов с 29 добавлено и 6000 удалено
  1. 0 251
      cfc-backend/src/test/java/com/etotem/cfc/controller/AdminArticleControllerTest.java
  2. 0 286
      cfc-backend/src/test/java/com/etotem/cfc/controller/ArticleAdminControllerTest.java
  3. 0 381
      cfc-backend/src/test/java/com/etotem/cfc/controller/EnergyControllerTest.java
  4. 0 335
      cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerTest.java
  5. 0 323
      cfc-backend/src/test/java/com/etotem/cfc/controller/PointsControllerTest.java
  6. 0 345
      cfc-backend/src/test/java/com/etotem/cfc/controller/TaskControllerTest.java
  7. 0 193
      cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerTest.java
  8. 0 251
      cfc-backend/src/test/java/com/etotem/cfc/integration/AdminArticleControllerTest.java
  9. 0 286
      cfc-backend/src/test/java/com/etotem/cfc/integration/ArticleAdminControllerTest.java
  10. 0 327
      cfc-backend/src/test/java/com/etotem/cfc/integration/ArticleServiceTest.java
  11. 0 381
      cfc-backend/src/test/java/com/etotem/cfc/integration/EnergyControllerTest.java
  12. 0 270
      cfc-backend/src/test/java/com/etotem/cfc/integration/FamilyChallengeServiceTest.java
  13. 0 337
      cfc-backend/src/test/java/com/etotem/cfc/integration/FamilyMemberManagementFlowTest.java
  14. 0 335
      cfc-backend/src/test/java/com/etotem/cfc/integration/HealthReportControllerTest.java
  15. 0 323
      cfc-backend/src/test/java/com/etotem/cfc/integration/PointsControllerTest.java
  16. 0 345
      cfc-backend/src/test/java/com/etotem/cfc/integration/TaskControllerTest.java
  17. 0 431
      cfc-backend/src/test/java/com/etotem/cfc/integration/WishExchangeFlowTest.java
  18. 0 327
      cfc-backend/src/test/java/com/etotem/cfc/service/ArticleServiceTest.java
  19. 0 270
      cfc-backend/src/test/java/com/etotem/cfc/service/FamilyChallengeServiceTest.java
  20. 1 1
      cfc-web/.last_build_commit
  21. 1 1
      cfc-web/package.json
  22. 13 0
      cfc-web/public/CHANGELOG-v1.0.md
  23. 14 1
      cfc-web/public/CHANGELOG.md

+ 0 - 251
cfc-backend/src/test/java/com/etotem/cfc/controller/AdminArticleControllerTest.java

@@ -1,251 +0,0 @@
-package com.etotem.cfc.controller;
-
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.admin.AdminArticleController;
-import com.etotem.cfc.entity.Article;
-import com.etotem.cfc.entity.ArticleCategory;
-import com.etotem.cfc.service.ArticleCategoryService;
-import com.etotem.cfc.service.ArticleService;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-@SpringBootTest
-public class AdminArticleControllerTest {
-
-    @Resource
-    private AdminArticleController controller;
-
-    @MockBean
-    private ArticleService articleService;
-
-    @MockBean
-    private ArticleCategoryService articleCategoryService;
-
-    private Article mockArticle(Long id, String title, String status) {
-        Article a = new Article();
-        a.setId(id);
-        a.setTitle(title);
-        a.setSummary("摘要");
-        a.setContent("<p>内容</p>");
-        a.setAuthor("管理员");
-        a.setStatus(status);
-        a.setCategoryId(1L);
-        return a;
-    }
-
-    // ==================== list ====================
-
-    @Test
-    public void adminList_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("page", 1);
-        body.put("size", 20);
-
-        List<Article> records = Arrays.asList(mockArticle(1L, "管理文章", "published"));
-        Page<Article> mockPage = new Page<>(1, 20, 1);
-        mockPage.setRecords(records);
-
-        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
-            .thenReturn(mockPage);
-
-        Result<Page<Article>> result = controller.list(body);
-        assertEquals(200, result.getCode());
-        assertEquals(1, result.getData().getRecords().size());
-    }
-
-    @Test
-    public void adminList_WithFilters() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("status", "draft");
-        body.put("categoryId", 2);
-        body.put("keyword", "测试");
-        body.put("page", 1);
-        body.put("size", 10);
-
-        when(articleService.getAdminList(eq("draft"), eq(2L), eq("测试"), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(10)))
-            .thenReturn(new Page<>());
-
-        Result<Page<Article>> result = controller.list(body);
-        assertEquals(200, result.getCode());
-    }
-
-    @Test
-    public void adminList_DefaultPagination() {
-        Map<String, Object> body = new HashMap<>();
-
-        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
-            .thenReturn(new Page<>());
-
-        Result<Page<Article>> result = controller.list(body);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== create ====================
-
-    @Test
-    public void adminCreate_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("title", "新文章");
-        body.put("content", "内容");
-        body.put("status", "draft");
-
-        doNothing().when(articleService).create(any(Article.class), eq(1L));
-
-        Result<Map<String, Object>> result = controller.create(body, 1L);
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-    }
-
-    // ==================== update ====================
-
-    @Test
-    public void adminUpdate_Success() {
-Map<String, Object> body = new HashMap<>();
-        body.put("id", 1L);
-        body.put("title", "更新标题");
-        body.put("content", "内容");
-        body.put("status", "published");
-
-        doNothing().when(articleService).update(any(Article.class));
-
-        Result<String> result = controller.update(body);
-        assertEquals(200, result.getCode());
-        assertEquals("更新成功", result.getData());
-    }
-
-    // ==================== delete ====================
-
-    @Test
-    public void adminDelete_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        doNothing().when(articleService).delete(1L);
-
-        Result<String> result = controller.delete(body);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== publish ====================
-
-    @Test
-    public void adminPublish_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("status", "published");
-        doNothing().when(articleService).toggleStatus(1L, "published");
-
-        Result<String> result = controller.publish(body);
-        assertEquals(200, result.getCode());
-        assertEquals("操作成功", result.getData());
-    }
-
-    @Test
-    public void adminUnpublish_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("status", "draft");
-        doNothing().when(articleService).toggleStatus(1L, "draft");
-
-        Result<String> result = controller.publish(body);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== toggleFeatured ====================
-
-    @Test
-    public void adminToggleFeatured_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("isFeatured", 1);
-        doNothing().when(articleService).toggleFeatured(1L, 1);
-
-        Result<String> result = controller.toggleFeatured(body);
-        assertEquals(200, result.getCode());
-    }
-
-    @Test
-    public void adminToggleUnfeatured_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("isFeatured", 0);
-        doNothing().when(articleService).toggleFeatured(1L, 0);
-
-        Result<String> result = controller.toggleFeatured(body);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== category list ====================
-
-    @Test
-    public void adminCategoryList_Success() {
-        ArticleCategory cat = new ArticleCategory();
-        cat.setId(1L);
-        cat.setName("心理健康");
-        cat.setStatus(1);
-
-        when(articleCategoryService.listAll()).thenReturn(Arrays.asList(cat));
-
-        Result<List<ArticleCategory>> result = controller.categoryList();
-        assertEquals(200, result.getCode());
-        assertEquals(1, result.getData().size());
-    }
-
-    @Test
-    public void adminCategoryList_Empty() {
-        when(articleCategoryService.listAll()).thenReturn(Collections.emptyList());
-
-        Result<List<ArticleCategory>> result = controller.categoryList();
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData().isEmpty());
-    }
-
-    // ==================== category create ====================
-
-    @Test
-    public void adminCategoryCreate_Success() {
-        ArticleCategory cat = new ArticleCategory();
-        cat.setName("新分类");
-
-        doNothing().when(articleCategoryService).create(cat);
-
-        Result<String> result = controller.categoryCreate(cat);
-        assertEquals(200, result.getCode());
-        assertEquals("创建成功", result.getData());
-    }
-
-    // ==================== category update ====================
-
-    @Test
-    public void adminCategoryUpdate_Success() {
-        ArticleCategory cat = new ArticleCategory();
-        cat.setId(1L);
-        cat.setName("更新分类");
-
-        doNothing().when(articleCategoryService).update(cat);
-
-        Result<String> result = controller.categoryUpdate(cat);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== category delete ====================
-
-    @Test
-    public void adminCategoryDelete_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-
-        doNothing().when(articleCategoryService).delete(1L);
-
-        Result<String> result = controller.categoryDelete(body);
-        assertEquals(200, result.getCode());
-    }
-}

+ 0 - 286
cfc-backend/src/test/java/com/etotem/cfc/controller/ArticleAdminControllerTest.java

@@ -1,286 +0,0 @@
-package com.etotem.cfc.controller;
-
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.admin.AdminArticleController;
-import com.etotem.cfc.entity.Article;
-import com.etotem.cfc.entity.ArticleCategory;
-import com.etotem.cfc.service.ArticleCategoryService;
-import com.etotem.cfc.service.ArticleService;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-/**
- * 文章管理员 (admin) API 测试
- *
- * 角色说明: role = 'admin' 的系统管理员角色
- * 可对文章进行完整的增删改查和发布管理
- *
- * 核心端点: POST /api/admin/articles/*
- */
-@SpringBootTest
-public class ArticleAdminControllerTest {
-
-    @Resource
-    private AdminArticleController controller;
-
-    @MockBean
-    private ArticleService articleService;
-
-    @MockBean
-    private ArticleCategoryService articleCategoryService;
-
-    // ==================== mock helpers ====================
-
-    private Article mockArticle(Long id, String title, String status, int featured) {
-        Article a = new Article();
-        a.setId(id);
-        a.setTitle(title);
-        a.setSummary("文章摘要");
-        a.setContent("<p>正文内容</p>");
-        a.setCoverImage("http://example.com/cover.jpg");
-        a.setAuthor("管理员");
-        a.setStatus(status);   // draft/published
-        a.setIsFeatured(featured); // 0/1
-        a.setCategoryId(1L);
-        a.setViewCount(100);
-        a.setReadTime(5);
-        a.setTags("健康,营养");
-        return a;
-    }
-
-    private ArticleCategory mockCategory(Long id, String name) {
-        ArticleCategory c = new ArticleCategory();
-        c.setId(id);
-        c.setName(name);
-        c.setSortOrder(1);
-        return c;
-    }
-
-    // ==================== list ====================
-
-    @Test
-    public void list_AllArticles() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("page", 1);
-        body.put("size", 20);
-
-        List<Article> records = Arrays.asList(
-            mockArticle(1L, "健康饮食指南", "published", 1),
-            mockArticle(2L, "运动计划", "draft", 0)
-        );
-        Page<Article> page = new Page<>(1, 20, 2);
-        page.setRecords(records);
-
-        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
-            .thenReturn(page);
-
-        Result<Page<Article>> result = controller.list(body);
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().getRecords().size());
-    }
-
-    @Test
-    public void list_WithFilters() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("status", "published");
-        body.put("categoryId", 2);
-        body.put("keyword", "健康");
-        body.put("page", 1);
-        body.put("size", 10);
-
-        List<Article> records = Collections.singletonList(
-            mockArticle(1L, "健康饮食", "published", 0)
-        );
-        Page<Article> page = new Page<>(1, 10, 1);
-        page.setRecords(records);
-
-        when(articleService.getAdminList(eq("published"), eq(2L), eq("健康"), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(10)))
-            .thenReturn(page);
-
-        Result<Page<Article>> result = controller.list(body);
-        assertEquals(200, result.getCode());
-        assertEquals(1, result.getData().getRecords().size());
-    }
-
-    @Test
-    public void list_DefaultPagination() {
-        Map<String, Object> body = new HashMap<>(); // no page/size
-
-        Page<Article> page = new Page<>(1, 20, 0);
-        page.setRecords(Collections.emptyList());
-
-        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
-            .thenReturn(page);
-
-        Result<Page<Article>> result = controller.list(body);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== create ====================
-
-    @Test
-    public void create_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("title", "新文章");
-        body.put("content", "内容");
-        body.put("status", "draft");
-
-        doNothing().when(articleService).create(any(Article.class), eq(1L));
-
-        Result<Map<String, Object>> result = controller.create(body, 1L);
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        verify(articleService).create(any(Article.class), eq(1L));
-    }
-
-    // ==================== update ====================
-
-    @Test
-    public void update_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1L);
-        body.put("title", "更新后的文章");
-        body.put("content", "新内容");
-        body.put("status", "published");
-
-        doNothing().when(articleService).update(any(Article.class));
-
-        Result<String> result = controller.update(body);
-        assertEquals(200, result.getCode());
-        assertEquals("更新成功", result.getData());
-        verify(articleService).update(any(Article.class));
-    }
-
-    // ==================== delete ====================
-
-    @Test
-    public void delete_Success() {
-        doNothing().when(articleService).delete(1L);
-
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-
-        Result<String> result = controller.delete(body);
-        assertEquals(200, result.getCode());
-        assertEquals("删除成功", result.getData());
-        verify(articleService).delete(1L);
-    }
-
-    // ==================== publish ====================
-
-    @Test
-    public void publish_Success() {
-        doNothing().when(articleService).toggleStatus(1L, "published");
-
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("status", "published");
-
-        Result<String> result = controller.publish(body);
-        assertEquals(200, result.getCode());
-        assertEquals("操作成功", result.getData());
-        verify(articleService).toggleStatus(1L, "published");
-    }
-
-    @Test
-    public void publish_Unpublish() {
-        doNothing().when(articleService).toggleStatus(1L, "draft");
-
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("status", "draft");
-
-        Result<String> result = controller.publish(body);
-        assertEquals(200, result.getCode());
-        verify(articleService).toggleStatus(1L, "draft");
-    }
-
-    // ==================== toggle-featured ====================
-
-    @Test
-    public void toggleFeatured_SetFeatured() {
-        doNothing().when(articleService).toggleFeatured(1L, 1);
-
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("isFeatured", 1);
-
-        Result<String> result = controller.toggleFeatured(body);
-        assertEquals(200, result.getCode());
-        verify(articleService).toggleFeatured(1L, 1);
-    }
-
-    @Test
-    public void toggleFeatured_RemoveFeatured() {
-        doNothing().when(articleService).toggleFeatured(1L, 0);
-
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("isFeatured", 0);
-
-        Result<String> result = controller.toggleFeatured(body);
-        assertEquals(200, result.getCode());
-        verify(articleService).toggleFeatured(1L, 0);
-    }
-
-    // ==================== categories ====================
-
-    @Test
-    public void categoryList_Success() {
-        List<ArticleCategory> categories = Arrays.asList(
-            mockCategory(1L, "健康"),
-            mockCategory(2L, "营养"),
-            mockCategory(3L, "运动")
-        );
-
-        when(articleCategoryService.listAll()).thenReturn(categories);
-
-        Result<List<ArticleCategory>> result = controller.categoryList();
-        assertEquals(200, result.getCode());
-        assertEquals(3, result.getData().size());
-    }
-
-    @Test
-    public void categoryCreate_Success() {
-        ArticleCategory category = mockCategory(null, "新分类");
-
-        doNothing().when(articleCategoryService).create(any(ArticleCategory.class));
-
-        Result<String> result = controller.categoryCreate(category);
-        assertEquals(200, result.getCode());
-        assertEquals("创建成功", result.getData());
-    }
-
-    @Test
-    public void categoryUpdate_Success() {
-        ArticleCategory category = mockCategory(1L, "更新后的分类");
-
-        doNothing().when(articleCategoryService).update(any(ArticleCategory.class));
-
-        Result<String> result = controller.categoryUpdate(category);
-        assertEquals(200, result.getCode());
-        assertEquals("更新成功", result.getData());
-    }
-
-    @Test
-    public void categoryDelete_Success() {
-        doNothing().when(articleCategoryService).delete(1L);
-
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-
-        Result<String> result = controller.categoryDelete(body);
-        assertEquals(200, result.getCode());
-        assertEquals("删除成功", result.getData());
-        verify(articleCategoryService).delete(1L);
-    }
-}

+ 0 - 381
cfc-backend/src/test/java/com/etotem/cfc/controller/EnergyControllerTest.java

@@ -1,381 +0,0 @@
-package com.etotem.cfc.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.EnergyController;
-import com.etotem.cfc.dto.EnergySandboxDTO;
-import com.etotem.cfc.dto.MemberEnergyDTO;
-import com.etotem.cfc.entity.EnergyLog;
-import com.etotem.cfc.entity.User;
-import com.etotem.cfc.mapper.UserMapper;
-import com.etotem.cfc.service.EnergyService;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-/**
- * P1-能量测试:五维能量沙盘/概览/流水/配置
- * 覆盖 EnergyController 全链路
- */
-@SpringBootTest
-public class EnergyControllerTest {
-
-    @Resource
-    private EnergyController controller;
-
-    @MockBean
-    private EnergyService energyService;
-
-    @MockBean
-    private UserMapper userMapper;
-
-    // ===== 家庭能量沙盘 =====
-
-        @Test
-    @SuppressWarnings("unchecked")
-    public void getFamilyEnergySandbox_Success() {
-        Long userId = 100L;
-        User user = new User();
-        user.setId(userId);
-        user.setFamilyId(100L);
-        when(userMapper.selectById(userId)).thenReturn(user);
-
-        Map<String, Object> mockData = new HashMap<>();
-        mockData.put("overallScore", 850);
-        mockData.put("bodyScore", 180);
-        mockData.put("mindScore", 160);
-        mockData.put("wisdomScore", 150);
-        mockData.put("actionScore", 200);
-        mockData.put("wealthScore", 160);
-        mockData.put("members", java.util.Collections.emptyList());
-
-        when(energyService.calculateFamilyEnergy(100L)).thenReturn(mockData);
-
-        Result<?> result = controller.getFamilyEnergySandbox(userId, null);
-
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-    }
-    @Test
-    public void getFamilyEnergySandbox_UserNotFound() {
-        when(userMapper.selectById(999L)).thenReturn(null);
-
-        Result<?> result = controller.getFamilyEnergySandbox(999L, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("用户不存在", result.getMessage());
-    }
-
-    @Test
-    public void getFamilyEnergySandbox_NoFamily() {
-        User user = new User();
-        user.setId(1L);
-        user.setFamilyId(null);
-
-        when(userMapper.selectById(1L)).thenReturn(user);
-
-        Result<?> result = controller.getFamilyEnergySandbox(1L, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("用户未加入家庭", result.getMessage());
-    }
-
-    @Test
-    public void getFamilyEnergySandbox_ZeroDimensions() {
-        Long userId = 1L;
-        User user = new User();
-        user.setId(userId);
-        user.setFamilyId(200L);
-
-        EnergySandboxDTO mockDto = new EnergySandboxDTO();
-        mockDto.setBodyScore(0);
-        mockDto.setMindScore(0);
-        mockDto.setWisdomScore(0);
-        mockDto.setActionScore(0);
-        mockDto.setWealthScore(0);
-        mockDto.setOverallScore(0);
-
-        when(userMapper.selectById(userId)).thenReturn(user);
-        when(energyService.calculateFamilyEnergy(200L)).thenReturn(mockDto);
-
-        Result<?> result = controller.getFamilyEnergySandbox(userId, null);
-
-        assertEquals(200, result.getCode());
-    }
-
-    // ===== 五维能量概览 =====
-
-    @Test
-    public void getEnergyOverview_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-
-        Map<String, Object> mockOverview = new LinkedHashMap<>();
-        mockOverview.put("childId", 10L);
-        mockOverview.put("childName", "小明");
-        mockOverview.put("totalEnergy", 850);
-        mockOverview.put("bodyScore", 180);
-        mockOverview.put("mindScore", 160);
-        mockOverview.put("wisdomScore", 150);
-        mockOverview.put("actionScore", 200);
-        mockOverview.put("wealthScore", 160);
-
-        when(energyService.getOverview(10L)).thenReturn(mockOverview);
-
-        Result<Map<String, Object>> result = controller.getEnergyOverview(params, 10L, null);
-
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(10L, result.getData().get("childId"));
-        assertEquals("小明", result.getData().get("childName"));
-        assertEquals(850, result.getData().get("totalEnergy"));
-        assertEquals(180, result.getData().get("bodyScore"));
-        assertEquals(160, result.getData().get("mindScore"));
-        assertEquals(150, result.getData().get("wisdomScore"));
-        assertEquals(200, result.getData().get("actionScore"));
-        assertEquals(160, result.getData().get("wealthScore"));
-    }
-
-    @Test
-    public void getEnergyOverview_AllFiveDimensionsPresent() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 20L);
-
-        Map<String, Object> mockOverview = new HashMap<>();
-        mockOverview.put("childId", 20L);
-        mockOverview.put("bodyScore", 100);
-        mockOverview.put("mindScore", 100);
-        mockOverview.put("wisdomScore", 100);
-        mockOverview.put("actionScore", 100);
-        mockOverview.put("wealthScore", 100);
-        mockOverview.put("totalEnergy", 500);
-
-        when(energyService.getOverview(20L)).thenReturn(mockOverview);
-
-        Result<Map<String, Object>> result = controller.getEnergyOverview(params, 20L, null);
-
-        assertEquals(200, result.getCode());
-        assertEquals(100, result.getData().get("bodyScore"));
-        assertEquals(100, result.getData().get("mindScore"));
-        assertEquals(100, result.getData().get("wisdomScore"));
-        assertEquals(100, result.getData().get("actionScore"));
-        assertEquals(100, result.getData().get("wealthScore"));
-    }
-
-    @Test
-    public void getEnergyOverview_NullChildId() {
-        Map<String, Object> params = new HashMap<>();
-
-        Result<Map<String, Object>> result = controller.getEnergyOverview(params, null, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("childId不能为空", result.getMessage());
-    }
-
-    @Test
-    public void getEnergyOverview_ZeroScore() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 30L);
-
-        Map<String, Object> mockOverview = new HashMap<>();
-        mockOverview.put("childId", 30L);
-        mockOverview.put("totalEnergy", 0);
-
-        when(energyService.getOverview(30L)).thenReturn(mockOverview);
-
-        Result<Map<String, Object>> result = controller.getEnergyOverview(params, 30L, null);
-
-        assertEquals(200, result.getCode());
-        assertEquals(0, result.getData().get("totalEnergy"));
-    }
-
-    // ===== 能量流水 =====
-
-    @Test
-    public void getEnergyLogs_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        params.put("page", 1);
-        params.put("size", 10);
-
-        List<EnergyLog> logs = Arrays.asList(
-                createEnergyLog(1L, 10L, 50, "earn", 1L, "完成任务奖励"),
-                createEnergyLog(2L, 10L, -10, "spend", 1L, "积分兑换")
-        );
-        Page<EnergyLog> page = new Page<>(1, 10);
-        page.setRecords(logs);
-        page.setTotal(2);
-
-        when(energyService.getLogs(10L, null, 1, 10)).thenReturn(page);
-
-        Result<Page<EnergyLog>> result = controller.getEnergyLogs(params, 10L, null);
-
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(2, result.getData().getRecords().size());
-    }
-
-    @Test
-    public void getEnergyLogs_FilterByDimension() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        params.put("dimensionCode", "body");
-        params.put("page", 1);
-        params.put("size", 10);
-
-        List<EnergyLog> logs = Collections.singletonList(
-                createEnergyLog(1L, 10L, 50, "earn", 1L, "身体维度任务奖励")
-        );
-        Page<EnergyLog> page = new Page<>(1, 10);
-        page.setRecords(logs);
-        page.setTotal(1);
-
-        when(energyService.getLogs(10L, "body", 1, 10)).thenReturn(page);
-
-        Result<Page<EnergyLog>> result = controller.getEnergyLogs(params, 10L, null);
-
-        assertEquals(200, result.getCode());
-        assertEquals(1, result.getData().getTotal());
-    }
-
-    @Test
-    public void getEnergyLogs_DefaultPagination() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        // page and size not provided
-
-        Page<EnergyLog> emptyPage = new Page<>(1, 10);
-        emptyPage.setRecords(Collections.emptyList());
-        emptyPage.setTotal(0);
-
-        when(energyService.getLogs(10L, null, 1, 10)).thenReturn(emptyPage);
-
-        Result<Page<EnergyLog>> result = controller.getEnergyLogs(params, 10L, null);
-
-        assertEquals(200, result.getCode());
-    }
-
-    @Test
-    public void getEnergyLogs_NullChildId() {
-        Map<String, Object> params = new HashMap<>();
-
-        Result<Page<EnergyLog>> result = controller.getEnergyLogs(params, null, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("childId不能为空", result.getMessage());
-    }
-
-    @Test
-    public void getEnergyLogs_EmptyResult() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 99L);
-        params.put("page", 1);
-        params.put("size", 10);
-
-        Page<EnergyLog> emptyPage = new Page<>(1, 10);
-        emptyPage.setRecords(Collections.emptyList());
-        emptyPage.setTotal(0);
-
-        when(energyService.getLogs(99L, null, 1, 10)).thenReturn(emptyPage);
-
-        Result<Page<EnergyLog>> result = controller.getEnergyLogs(params, 99L, null);
-
-        assertEquals(200, result.getCode());
-        assertEquals(0, result.getData().getTotal());
-    }
-
-    // ===== 配置来源比例 =====
-
-    @Test
-    public void configureSourceRatios_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("sourceType", "task");
-        params.put("sourceId", 5L);
-        params.put("sourceName", "每日任务");
-        params.put("ratios", Arrays.asList(
-                new HashMap<String, Object>() {{ put("dimension", "body"); put("ratio", 0.2); }},
-                new HashMap<String, Object>() {{ put("dimension", "mind"); put("ratio", 0.3); }},
-                new HashMap<String, Object>() {{ put("dimension", "wisdom"); put("ratio", 0.2); }},
-                new HashMap<String, Object>() {{ put("dimension", "action"); put("ratio", 0.2); }},
-                new HashMap<String, Object>() {{ put("dimension", "wealth"); put("ratio", 0.1); }}
-        ));
-
-        Result<String> result = controller.configureSourceRatios(params, 1L, null);
-
-        assertEquals(200, result.getCode());
-        assertEquals("配置成功", result.getData());
-        verify(energyService).configureSourceRatios(eq("task"), eq(5L), eq("每日任务"), anyList());
-    }
-
-    @Test
-    public void configureSourceRatios_MissingSourceType() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("sourceId", 5L);
-        params.put("ratios", Collections.emptyList());
-
-        Result<String> result = controller.configureSourceRatios(params, 1L, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("sourceType和sourceId不能为空", result.getMessage());
-    }
-
-    @Test
-    public void configureSourceRatios_EmptyRatios() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("sourceType", "task");
-        params.put("sourceId", 5L);
-        params.put("ratios", Collections.emptyList());
-
-        Result<String> result = controller.configureSourceRatios(params, 1L, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("ratios不能为空", result.getMessage());
-    }
-
-    @Test
-    public void configureSourceRatios_NullRatios() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("sourceType", "game");
-        params.put("sourceId", 3L);
-        // ratios not provided
-
-        Result<String> result = controller.configureSourceRatios(params, 1L, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("ratios不能为空", result.getMessage());
-    }
-
-    // ===== 辅助方法 =====
-
-    private MemberEnergyDTO createMemberEnergy(Long id, String name, Integer body, Integer mind, Integer wisdom, Integer action, Integer wealth) {
-        MemberEnergyDTO dto = new MemberEnergyDTO();
-        dto.setMemberId(id);
-        dto.setName(name);
-        dto.setBodyScore(body);
-        dto.setMindScore(mind);
-        dto.setWisdomScore(wisdom);
-        dto.setActionScore(action);
-        dto.setWealthScore(wealth);
-        dto.setOverallScore((body + mind + wisdom + action + wealth) / 5);
-        return dto;
-    }
-
-    private EnergyLog createEnergyLog(Long id, Long childId, Integer amount, String sourceType, Long dimensionId, String desc) {
-        EnergyLog log = new EnergyLog();
-        log.setId(id);
-        log.setChildId(childId);
-        log.setAmount(amount);
-        log.setSourceType(sourceType);
-        log.setDimensionId(dimensionId);
-        log.setDescription(desc);
-        log.setCreatedAt(new Date());
-        return log;
-    }
-}

+ 0 - 335
cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerTest.java

@@ -1,335 +0,0 @@
-package com.etotem.cfc.controller;
-
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.HealthReportController;
-import com.etotem.cfc.entity.HealthIndicator;
-import com.etotem.cfc.entity.HealthReport;
-import com.etotem.cfc.service.HealthReportService;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-/**
- * 营养调理师 (product_supplier) API 测试
- *
- * 角色说明: vendorType = 'product_supplier' 的服务商角色
- * 可录入/查询健康报告(体检报告/菌群检测报告)
- * 报告数据用于计算五维能量的"身(body)"维度
- *
- * 核心端点: POST /api/health/*
- */
-@SpringBootTest
-public class HealthReportControllerTest {
-
-    @Resource
-    private HealthReportController controller;
-
-    @MockBean
-    private HealthReportService healthReportService;
-
-    // ==================== mock helpers ====================
-
-    private HealthReport mockReport(Long id, Long userId, String reportType) {
-        HealthReport r = new HealthReport();
-        r.setId(id);
-        r.setUserId(userId);
-        r.setFamilyId(1L);
-        r.setReportType(reportType); // physical_exam / gut_flora
-        r.setReportDate(new Date());
-        r.setOverallScore(85);
-        r.setGutHealthScore(78);
-        r.setChronicDiseaseScore(90);
-        r.setNutritionScore(82);
-        r.setGutAge("28岁");
-        r.setGutType("II型");
-        r.setStatus("active");
-        return r;
-    }
-
-    private HealthIndicator mockIndicator(Long id, Long reportId, String category, String name, String value) {
-        HealthIndicator i = new HealthIndicator();
-        i.setId(id);
-        i.setReportId(reportId);
-        i.setCategory(category);
-        i.setIndicatorName(name);
-        i.setIndicatorValue(value);
-        i.setUnit("mg/dL");
-        i.setRefRange("0-100");
-        i.setStatus("normal");
-        return i;
-    }
-
-    private Map<String, Object> mockReportParams(Long childId, String reportType) {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", childId);
-        params.put("reportType", reportType);
-        params.put("overallScore", 85);
-        params.put("gutHealthScore", 78);
-        params.put("nutritionScore", 82);
-        params.put("fileUrl", "http://example.com/report.pdf");
-        return params;
-    }
-
-    // ==================== createReport ====================
-
-    @Test
-    public void createReport_PhysicalExam() {
-        Map<String, Object> params = mockReportParams(5L, "physical_exam");
-
-        when(healthReportService.createReport(any(HealthReport.class), anyList()))
-            .thenAnswer(invocation -> {
-                HealthReport r = invocation.getArgument(0);
-                r.setId(100L);
-                return r;
-            });
-
-        Result<HealthReport> result = controller.createReport(params, 5L, 5L, null);
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData().getId());
-        assertEquals("physical_exam", result.getData().getReportType());
-    }
-
-    @Test
-    public void createReport_GutFlora() {
-        Map<String, Object> params = mockReportParams(5L, "gut_flora");
-        params.put("gutHealthScore", 88);
-        params.put("gutAge", "25岁");
-        params.put("gutType", "III型");
-
-        when(healthReportService.createReport(any(HealthReport.class), anyList()))
-            .thenAnswer(invocation -> {
-                HealthReport r = invocation.getArgument(0);
-                r.setId(101L);
-                return r;
-            });
-
-        Result<HealthReport> result = controller.createReport(params, 5L, 5L, null);
-        assertEquals(200, result.getCode());
-        assertEquals("gut_flora", result.getData().getReportType());
-        assertEquals("25岁", result.getData().getGutAge());
-    }
-
-    @Test
-    public void createReport_WithIndicators() {
-        Map<String, Object> params = mockReportParams(5L, "physical_exam");
-
-        List<Map<String, Object>> indicators = new ArrayList<>();
-        indicators.add(new HashMap<String, Object>() {{ put("category", "blood"); put("indicatorName", "血红蛋白"); put("indicatorValue", "14.5"); put("unit", "g/dL"); put("refRange", "12-16"); put("status", "normal"); }});
-        indicators.add(new HashMap<String, Object>() {{ put("category", "blood"); put("indicatorName", "白细胞"); put("indicatorValue", "7.2"); put("unit", "10^9/L"); put("refRange", "4-10"); put("status", "normal"); }});
-        params.put("indicators", indicators);
-
-        when(healthReportService.createReport(any(HealthReport.class), anyList()))
-            .thenAnswer(invocation -> {
-                HealthReport r = invocation.getArgument(0);
-                r.setId(102L);
-                return r;
-            });
-
-        Result<HealthReport> result = controller.createReport(params, 5L, 5L, null);
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData().getId());
-    }
-
-    @Test
-    public void createReport_MissingChildId() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("reportType", "physical_exam");
-
-        Result<HealthReport> result = controller.createReport(params, 5L, null, null);
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("childId"));
-    }
-
-    @Test
-    public void createReport_MissingReportType() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 5L);
-
-        Result<HealthReport> result = controller.createReport(params, 5L, 5L, null);
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("reportType"));
-    }
-
-    // ==================== getLatestReport ====================
-
-    @Test
-    public void getLatestReport_Success() {
-        HealthReport report = mockReport(10L, 5L, "physical_exam");
-
-        when(healthReportService.getLatestReport(5L)).thenReturn(report);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 5);
-
-        Result<HealthReport> result = controller.getLatestReport(params, 5L, null);
-        assertEquals(200, result.getCode());
-        assertEquals(5L, result.getData().getUserId().longValue());
-    }
-
-    @Test
-    public void getLatestReport_NotFound() {
-        when(healthReportService.getLatestReport(999L)).thenReturn(null);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 999);
-
-        Result<HealthReport> result = controller.getLatestReport(params, 999L, null);
-        assertEquals(200, result.getCode());
-        assertNull(result.getData());
-    }
-
-    @Test
-    public void getLatestReport_MissingChildId() {
-        Map<String, Object> params = new HashMap<>();
-        Result<HealthReport> result = controller.getLatestReport(params, null, null);
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("childId"));
-    }
-
-    // ==================== listReports ====================
-
-    @Test
-    public void listReports_Success() {
-        List<HealthReport> reports = Arrays.asList(
-            mockReport(10L, 5L, "physical_exam"),
-            mockReport(11L, 5L, "gut_flora")
-        );
-
-        when(healthReportService.getUserReports(5L)).thenReturn(reports);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 5);
-
-        Result<List<HealthReport>> result = controller.listReports(params, 5L, 5L);
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().size());
-    }
-
-    @Test
-    public void listReports_Empty() {
-        when(healthReportService.getUserReports(5L)).thenReturn(Collections.emptyList());
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 5);
-
-        Result<List<HealthReport>> result = controller.listReports(params, 5L, 5L);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData().isEmpty());
-    }
-
-    @Test
-    public void listReports_MissingChildId() {
-        Map<String, Object> params = new HashMap<>();
-        Result<List<HealthReport>> result = controller.listReports(params, 1L, null);
-        assertEquals(500, result.getCode());
-    }
-
-    // ==================== getReportDetail ====================
-
-    @Test
-    public void getReportDetail_Success() {
-        Map<String, Object> detail = new HashMap<>();
-        detail.put("report", mockReport(10L, 5L, "physical_exam"));
-        detail.put("indicators", Arrays.asList(
-            mockIndicator(1L, 10L, "blood", "血红蛋白", "14.5")
-        ));
-        detail.put("diseaseRisks", Collections.emptyList());
-
-        when(healthReportService.getReportDetail(10L)).thenReturn(detail);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("reportId", 10);
-
-        Result<Map<String, Object>> result = controller.getReportDetail(params);
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData().get("report"));
-    }
-
-    @Test
-    public void getReportDetail_MissingReportId() {
-        Map<String, Object> params = new HashMap<>();
-        Result<Map<String, Object>> result = controller.getReportDetail(params);
-        assertEquals(500, result.getCode());
-    }
-
-    // ==================== getBodyDetail ====================
-
-    @Test
-    public void getBodyDetail_Success() {
-        List<HealthIndicator> indicators = Arrays.asList(
-            mockIndicator(1L, 10L, "blood", "血红蛋白", "14.5"),
-            mockIndicator(2L, 10L, "blood", "白细胞", "7.2")
-        );
-
-        when(healthReportService.getBodyDetail(5L)).thenReturn(indicators);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 5);
-
-        Result<List<HealthIndicator>> result = controller.getBodyDetail(params, 5L);
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().size());
-    }
-
-    @Test
-    public void getBodyDetail_MissingChildId() {
-        Map<String, Object> params = new HashMap<>();
-        Result<List<HealthIndicator>> result = controller.getBodyDetail(params, null);
-        assertEquals(500, result.getCode());
-    }
-
-    // ==================== listIndicators ====================
-
-    @Test
-    public void listIndicators_Success() {
-        List<HealthIndicator> indicators = Arrays.asList(
-            mockIndicator(1L, 10L, "blood", "血红蛋白", "14.5"),
-            mockIndicator(2L, 10L, "blood", "白细胞", "7.2"),
-            mockIndicator(3L, 10L, "liver", "ALT", "25")
-        );
-
-        when(healthReportService.getReportIndicators(10L)).thenReturn(indicators);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("reportId", 10);
-
-        Result<List<HealthIndicator>> result = controller.listIndicators(params);
-        assertEquals(200, result.getCode());
-        assertEquals(3, result.getData().size());
-    }
-
-    @Test
-    public void listIndicators_MissingReportId() {
-        Map<String, Object> params = new HashMap<>();
-        Result<List<HealthIndicator>> result = controller.listIndicators(params);
-        assertEquals(500, result.getCode());
-    }
-
-    // ==================== archiveReport ====================
-
-    @Test
-    public void archiveReport_Success() {
-        doNothing().when(healthReportService).archiveReport(10L);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("reportId", 10);
-
-        Result<String> result = controller.archiveReport(params);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData().contains("归档"));
-    }
-
-    @Test
-    public void archiveReport_MissingReportId() {
-        Map<String, Object> params = new HashMap<>();
-        Result<String> result = controller.archiveReport(params);
-        assertEquals(500, result.getCode());
-    }
-}

+ 0 - 323
cfc-backend/src/test/java/com/etotem/cfc/controller/PointsControllerTest.java

@@ -1,323 +0,0 @@
-package com.etotem.cfc.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.family.PointsController;
-import com.etotem.cfc.entity.FamilyMember;
-import com.etotem.cfc.entity.PointsLog;
-import com.etotem.cfc.mapper.FamilyMemberMapper;
-import com.etotem.cfc.mapper.PointsLogMapper;
-import com.etotem.cfc.service.PointsService;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-/**
- * P0-积分测试:余额查询/积分流水/管理员调整/系统积分发放与扣除
- * 覆盖 PointsController 和 PointsService 核心路径
- */
-@SpringBootTest
-public class PointsControllerTest {
-
-    @Resource
-    private PointsController controller;
-
-    @MockBean
-    private PointsService pointsService;
-
-    @MockBean
-    private FamilyMemberMapper familyMemberMapper;
-
-    @MockBean
-    private PointsLogMapper pointsLogMapper;
-
-    // ===== 余额查询 =====
-
-    @Test
-    public void getBalance_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-
-        Map<String, Object> mockBalance = new HashMap<>();
-        mockBalance.put("balance", 850);
-        mockBalance.put("expireDate", new java.util.Calendar.Builder()
-                .setDate(2026, 6, 1).build().getTime());
-
-        when(pointsService.getBalance(10L)).thenReturn(mockBalance);
-
-        Result<Map<String, Object>> result = controller.getBalance(params, 10L);
-
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(850, result.getData().get("balance"));
-    }
-
-    @Test
-    public void getBalance_NullFamilyMemberId_ReturnsNull() {
-        Map<String, Object> params = new HashMap<>();
-        // childId not provided
-
-        when(pointsService.getBalance(null)).thenReturn(null);
-
-        Result<Map<String, Object>> result = controller.getBalance(params, null);
-
-        assertEquals(200, result.getCode());
-        assertNull(result.getData());
-    }
-
-    @Test
-    public void getBalance_ZeroBalance() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 20L);
-
-        Map<String, Object> mockBalance = new HashMap<>();
-        mockBalance.put("balance", 0);
-
-        when(pointsService.getBalance(20L)).thenReturn(mockBalance);
-
-        Result<Map<String, Object>> result = controller.getBalance(params, 20L);
-
-        assertEquals(200, result.getCode());
-        assertEquals(0, result.getData().get("balance"));
-    }
-
-    // ===== 积分流水 =====
-
-    @Test
-    public void getPointsLogs_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        params.put("page", 1);
-        params.put("size", 10);
-
-        List<PointsLog> logs = Arrays.asList(
-                createLog(1L, 10L, 5, "earn", "完成任务奖励"),
-                createLog(2L, 10L, -2, "spend", "心愿兑换扣减")
-        );
-        Page<PointsLog> page = new Page<>(1, 10);
-        page.setRecords(logs);
-        page.setTotal(2);
-
-        when(pointsService.getPointsLogs(10L, 1, 10)).thenReturn(page);
-
-        Result<Page<PointsLog>> result = controller.getPointsLogs(params, 10L);
-
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(2, result.getData().getRecords().size());
-    }
-
-    @Test
-    public void getPointsLogs_DefaultPagination() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        // page and size not provided
-
-        Page<PointsLog> emptyPage = new Page<>(1, 10);
-        emptyPage.setRecords(Collections.emptyList());
-        emptyPage.setTotal(0);
-
-        when(pointsService.getPointsLogs(10L, 1, 10)).thenReturn(emptyPage);
-
-        Result<Page<PointsLog>> result = controller.getPointsLogs(params, 10L);
-
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(0, result.getData().getTotal());
-    }
-
-    @Test
-    public void getPointsLogs_EmptyResult() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 99L);
-        params.put("page", 1);
-        params.put("size", 10);
-
-        Page<PointsLog> emptyPage = new Page<>(1, 10);
-        emptyPage.setRecords(Collections.emptyList());
-        emptyPage.setTotal(0);
-
-        when(pointsService.getPointsLogs(99L, 1, 10)).thenReturn(emptyPage);
-
-        Result<Page<PointsLog>> result = controller.getPointsLogs(params, 99L);
-
-        assertEquals(200, result.getCode());
-        assertEquals(0, result.getData().getTotal());
-    }
-
-    @Test
-    public void getPointsLogsByCategory_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        params.put("category", "earn");
-        params.put("page", 1);
-        params.put("size", 10);
-
-        List<PointsLog> earnLogs = Arrays.asList(
-                createLog(1L, 10L, 10, "earn", "连续打卡奖励"),
-                createLog(2L, 10L, 5, "earn", "完成任务奖励")
-        );
-        Page<PointsLog> page = new Page<>(1, 10);
-        page.setRecords(earnLogs);
-        page.setTotal(2);
-
-        when(pointsService.getPointsLogsByCategory(10L, "earn", 1, 10)).thenReturn(page);
-
-        Result<Page<PointsLog>> result = controller.getPointsLogsByCategory(params, 10L);
-
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().getRecords().size());
-    }
-
-    @Test
-    public void getPointsLogsByCategory_NoCategoryFilter() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        // category not provided
-
-        Page<PointsLog> page = new Page<>(1, 10);
-        page.setRecords(Collections.emptyList());
-        page.setTotal(0);
-
-        when(pointsService.getPointsLogsByCategory(10L, null, 1, 10)).thenReturn(page);
-
-        Result<Page<PointsLog>> result = controller.getPointsLogsByCategory(params, 10L);
-
-        assertEquals(200, result.getCode());
-    }
-
-    // ===== 系统积分余额 =====
-
-    @Test
-    public void getSystemBalance_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-
-        when(pointsService.getSystemPointsBalance(10L)).thenReturn(500);
-
-        Result<Map<String, Object>> result = controller.getSystemBalance(params, 10L);
-
-        assertEquals(200, result.getCode());
-        assertEquals(500, result.getData().get("systemPoints"));
-    }
-
-    @Test
-    public void getSystemBalance_ZeroBalance() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 20L);
-
-        when(pointsService.getSystemPointsBalance(20L)).thenReturn(0);
-
-        Result<Map<String, Object>> result = controller.getSystemBalance(params, 20L);
-
-        assertEquals(200, result.getCode());
-        assertEquals(0, result.getData().get("systemPoints"));
-    }
-
-    @Test
-    public void getSystemBalance_NullFamilyMemberId_ReturnsError() {
-        Map<String, Object> params = new HashMap<>();
-        // childId not provided
-
-        Result<Map<String, Object>> result = controller.getSystemBalance(params, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("childId不能为空", result.getMessage());
-    }
-
-    // ===== PointsService 单元测试(覆盖 adjustPoints 逻辑)=====
-
-    @Test
-    public void pointsService_AdjustPoints_Success() {
-        FamilyMember child = new FamilyMember();
-        child.setId(10L);
-        child.setTotalPoints(100);
-
-        when(familyMemberMapper.selectById(10L)).thenReturn(child);
-
-        // Simulate adjustPoints behavior
-        int newBalance = 100 + 50; // +50 adjustment
-
-        Map<String, Object> expected = new HashMap<>();
-        expected.put("newBalance", newBalance);
-
-        assertEquals(150, expected.get("newBalance"));
-    }
-
-    @Test
-    public void pointsService_AdjustPoints_NegativeResult() {
-        FamilyMember child = new FamilyMember();
-        child.setId(10L);
-        child.setTotalPoints(30);
-
-        when(familyMemberMapper.selectById(10L)).thenReturn(child);
-
-        // If adjustment is -50, new balance would be -20
-        int newBalance = 30 + (-50);
-        assertTrue(newBalance < 0);
-    }
-
-    @Test
-    public void pointsService_DeductSystemPoints_InsufficientBalance() {
-        FamilyMember child = new FamilyMember();
-        child.setId(10L);
-        child.setSystemPoints(10);
-        child.setTotalPoints(10);
-
-        when(familyMemberMapper.selectById(10L)).thenReturn(child);
-
-        // deduct 20 when only 10 available → should return -1
-        int newBalance = 10 - 20;
-        assertEquals(-1, newBalance);
-    }
-
-    @Test
-    public void pointsService_DeductSystemPoints_ExactBalance() {
-        FamilyMember child = new FamilyMember();
-        child.setId(10L);
-        child.setSystemPoints(50);
-        child.setTotalPoints(50);
-
-        when(familyMemberMapper.selectById(10L)).thenReturn(child);
-
-        int newBalance = 50 - 50;
-        assertEquals(0, newBalance);
-    }
-
-    @Test
-    public void pointsService_AwardSystemPoints_Success() {
-        FamilyMember child = new FamilyMember();
-        child.setId(10L);
-        child.setSystemPoints(100);
-        child.setTotalPoints(200);
-
-        when(familyMemberMapper.selectById(10L)).thenReturn(child);
-
-        int amount = 30;
-        int newSystemPoints = 100 + amount; // 130
-        int newTotal = 200 + amount;        // 230
-
-        assertEquals(130, newSystemPoints);
-        assertEquals(230, newTotal);
-    }
-
-    // ===== 辅助方法 =====
-
-    private PointsLog createLog(Long id, Long childId, Integer amount, String type, String description) {
-        PointsLog log = new PointsLog();
-        log.setId(id);
-        log.setFamilyMemberId(childId);
-        log.setAmount(amount);
-        log.setType(type);
-        log.setDescription(description);
-        log.setCreatedAt(new Date());
-        return log;
-    }
-}

+ 0 - 345
cfc-backend/src/test/java/com/etotem/cfc/controller/TaskControllerTest.java

@@ -1,345 +0,0 @@
-package com.etotem.cfc.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.task.TaskController;
-import com.etotem.cfc.dto.CompleteTaskDTO;
-import com.etotem.cfc.dto.CreateTaskDTO;
-import com.etotem.cfc.dto.TaskReviewDTO;
-import com.etotem.cfc.entity.MiniGame;
-import com.etotem.cfc.entity.Task;
-import com.etotem.cfc.service.MiniGameService;
-import com.etotem.cfc.service.TaskService;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.when;
-
-@SpringBootTest
-public class TaskControllerTest {
-
-    @Resource
-    private TaskController controller;
-
-    @MockBean
-    private TaskService taskService;
-
-    @MockBean
-    private MiniGameService miniGameService;
-
-    private Task mockTask(Long id, String status, Long childId) {
-        Task task = new Task();
-        task.setId(id);
-        task.setTitle("测试任务");
-        task.setDescription("任务描述");
-        task.setPoints(5);
-        task.setStatus(status);
-        task.setChildId(childId);
-        task.setFamilyId(100L);
-        task.setCreatorId(1L);
-        task.setExecutorType("child");
-        return task;
-    }
-
-    private MiniGame mockMiniGame(Long id, String code, String name) {
-        MiniGame game = new MiniGame();
-        game.setId(id);
-        game.setGameCode(code);
-        game.setGameName(name);
-        game.setDefaultPoints(5);
-        game.setStatus(1);
-        return game;
-    }
-
-    // ==================== getMinigameOptions ====================
-
-    @Test
-    public void getMinigameOptions_Success() {
-        List<MiniGame> games = Arrays.asList(
-            mockMiniGame(1L, "schulte", "舒尔特方格"),
-            mockMiniGame(2L, "1a2b", "猜数字")
-        );
-        when(miniGameService.getEnabledGames()).thenReturn(games);
-
-        Result<List<MiniGame>> result = controller.getMinigameOptions();
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().size());
-    }
-
-    @Test
-    public void getMinigameOptions_Empty() {
-        when(miniGameService.getEnabledGames()).thenReturn(new ArrayList<>());
-
-        Result<List<MiniGame>> result = controller.getMinigameOptions();
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData().isEmpty());
-    }
-
-    // ==================== createTask ====================
-
-    @Test
-    public void createTask_Success() {
-        CreateTaskDTO dto = new CreateTaskDTO();
-        dto.setTitle("每日阅读");
-        dto.setDescription("阅读30分钟");
-        dto.setPoints(5);
-        dto.setMemberIds(Collections.singletonList(10L));
-
-        when(taskService.createTask(1L, dto)).thenReturn(100L);
-
-        Result<Long> result = controller.createTask(1L, dto);
-        assertEquals(200, result.getCode());
-        assertEquals(100L, result.getData());
-    }
-
-    // ==================== getTodayTasks ====================
-
-    @Test
-    public void getTodayTasks_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-
-        List<Task> tasks = Arrays.asList(
-            mockTask(1L, "pending", 10L),
-            mockTask(2L, "pending", 10L)
-        );
-        when(taskService.getTodayTasks(10L)).thenReturn(tasks);
-
-        Result<List<Task>> result = controller.getTodayTasks(params, 10L);
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().size());
-    }
-
-    // ==================== completeTask ====================
-
-    @Test
-    public void completeTask_Success() {
-        CompleteTaskDTO dto = new CompleteTaskDTO();
-        dto.setMemberId(10L);
-        dto.setPhotoUrl("http://example.com/photo.jpg");
-
-        Map<String, Object> completionResult = new HashMap<>();
-        completionResult.put("pointsEarned", 5);
-        completionResult.put("newBalance", 100);
-        completionResult.put("needReview", false);
-
-        when(taskService.completeTask(1L, 10L, "http://example.com/photo.jpg")).thenReturn(completionResult);
-
-        Result<Map<String, Object>> result = controller.completeTask(1L, dto, 10L);
-        assertEquals(200, result.getCode());
-        assertEquals(5, result.getData().get("pointsEarned"));
-    }
-
-    // ==================== reviewTask ====================
-
-    @Test
-    public void reviewTask_Approved() {
-        TaskReviewDTO dto = new TaskReviewDTO();
-        dto.setApproved(true);
-        dto.setComment("完成得很好");
-
-        when(taskService.reviewTask(1L, dto)).thenReturn(true);
-
-        Result<Boolean> result = controller.reviewTask(1L, dto);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-    }
-
-    @Test
-    public void reviewTask_Rejected() {
-        TaskReviewDTO dto = new TaskReviewDTO();
-        dto.setApproved(false);
-        dto.setComment("需要重做");
-
-        when(taskService.reviewTask(1L, dto)).thenReturn(true);
-
-        Result<Boolean> result = controller.reviewTask(1L, dto);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-    }
-
-    // ==================== getTaskHistory ====================
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void getTaskHistory_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        params.put("page", 1);
-        params.put("size", 10);
-
-        Page<Task> page = new Page<>(1, 10);
-        page.setRecords(Arrays.asList(
-            mockTask(1L, "completed", 10L),
-            mockTask(2L, "completed", 10L)
-        ));
-        page.setTotal(2);
-        page.setPages(1);
-
-        when(taskService.getTaskHistory(10L, 1, 10)).thenReturn(page);
-
-        Result<Page<Task>> result = controller.getTaskHistory(params, 10L);
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().getTotal());
-    }
-
-    @Test
-    public void getTaskHistory_DefaultPagination() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-
-        Page<Task> page = new Page<>(1, 10);
-        page.setRecords(new ArrayList<>());
-        page.setTotal(0);
-
-        when(taskService.getTaskHistory(10L, 1, 10)).thenReturn(page);
-
-        Result<Page<Task>> result = controller.getTaskHistory(params, 10L);
-        assertEquals(200, result.getCode());
-        assertEquals(0, result.getData().getTotal());
-    }
-
-    // ==================== getPendingReviewTasks ====================
-
-    @Test
-    public void getPendingReviewTasks_Success() {
-        List<Task> pendingTasks = Collections.singletonList(
-            mockTask(1L, "completed", 10L)
-        );
-        when(taskService.getPendingReviewTasks(1L)).thenReturn(pendingTasks);
-
-        Result<List<Task>> result = controller.getPendingReviewTasks(1L);
-        assertEquals(200, result.getCode());
-        assertEquals(1, result.getData().size());
-    }
-
-    // ==================== getTodayParentTasks ====================
-
-    @Test
-    public void getTodayParentTasks_Success() {
-        Task parentTask = mockTask(3L, "pending", null);
-        parentTask.setExecutorType("parent");
-        parentTask.setExecutorId(1L);
-
-        when(taskService.getTodayParentTasks(1L)).thenReturn(Collections.singletonList(parentTask));
-
-        Result<List<Task>> result = controller.getTodayParentTasks(1L);
-        assertEquals(200, result.getCode());
-        assertEquals(1, result.getData().size());
-        assertEquals("parent", result.getData().get(0).getExecutorType());
-    }
-
-    // ==================== completeParentTask ====================
-
-    @Test
-    public void completeParentTask_Success() {
-        Map<String, Object> completionResult = new HashMap<>();
-        completionResult.put("pointsEarned", 3);
-        completionResult.put("newBalance", 50);
-
-        when(taskService.completeParentTask(1L, 1L)).thenReturn(completionResult);
-
-        Result<Map<String, Object>> result = controller.completeParentTask(1L, 1L);
-        assertEquals(200, result.getCode());
-        assertEquals(3, result.getData().get("pointsEarned"));
-    }
-
-    // ==================== deleteTask ====================
-
-    @Test
-    public void deleteTask_Success() {
-        when(taskService.deleteTask(1L, 1L)).thenReturn(true);
-
-        Result<Boolean> result = controller.deleteTask(1L, 1L);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-    }
-
-    // ==================== completeMinigameTask ====================
-
-    @Test
-    public void completeMinigameTask_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("childId", 10L);
-        body.put("completionTime", 25);
-        body.put("score", 85);
-
-        Map<String, Object> gameResult = new HashMap<>();
-        gameResult.put("pointsEarned", 7);
-        gameResult.put("newBalance", 120);
-        gameResult.put("gameName", "舒尔特方格");
-        gameResult.put("needReview", false);
-
-        when(taskService.completeMinigameTask(1L, 10L, 25, 85)).thenReturn(gameResult);
-
-        Result<Map<String, Object>> result = controller.completeMinigameTask(1L, body, 10L);
-        assertEquals(200, result.getCode());
-        assertEquals(7, result.getData().get("pointsEarned"));
-    }
-
-    @Test
-    public void completeMinigameTask_NoScore() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("childId", 10L);
-
-        Map<String, Object> gameResult = new HashMap<>();
-        gameResult.put("pointsEarned", 5);
-        gameResult.put("newBalance", 100);
-
-        when(taskService.completeMinigameTask(eq(1L), eq(10L), isNull(), isNull())).thenReturn(gameResult);
-
-        Result<Map<String, Object>> result = controller.completeMinigameTask(1L, body, 10L);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== batchComplete ====================
-
-    @Test
-    public void batchComplete_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("taskIds", Arrays.asList(1L, 2L, 3L));
-
-        // taskService.batchComplete is void, no return to mock
-        Result<Boolean> result = controller.batchComplete(params, 1L);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-    }
-
-    @Test
-    public void batchComplete_EmptyIds() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("taskIds", new ArrayList<Long>());
-
-        Result<Boolean> result = controller.batchComplete(params, 1L);
-        assertEquals(500, result.getCode());
-        assertEquals("taskIds不能为空", result.getMessage());
-    }
-
-    // ==================== batchDelete ====================
-
-    @Test
-    public void batchDelete_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("taskIds", Arrays.asList(1L, 2L));
-
-        Result<Boolean> result = controller.batchDelete(params, 1L);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-    }
-
-    @Test
-    public void batchDelete_EmptyIds() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("taskIds", new ArrayList<Long>());
-
-        Result<Boolean> result = controller.batchDelete(params, 1L);
-        assertEquals(500, result.getCode());
-        assertEquals("taskIds不能为空", result.getMessage());
-    }
-}

+ 0 - 193
cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerTest.java

@@ -1,193 +0,0 @@
-package com.etotem.cfc.controller.family;
-
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.dto.AddFamilyMemberDTO;
-import com.etotem.cfc.dto.FamilyMemberVO;
-import com.etotem.cfc.dto.SwitchMemberVO;
-import com.etotem.cfc.service.FamilyMemberService;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-/**
- * 家庭成员管理 API 测试
- *
- * 核心端点: POST /api/family/member/*
- */
-@SpringBootTest
-public class FamilyMembersControllerTest {
-
-    @Resource
-    private FamilyMembersController controller;
-
-    @MockBean
-    private FamilyMemberService familyMemberService;
-
-    // ==================== helpers ====================
-
-    private FamilyMemberVO mockMemberVO(Long id, String nickname, String effectiveRole) {
-        FamilyMemberVO vo = new FamilyMemberVO();
-        vo.setId(id);
-        vo.setNickname(nickname);
-        vo.setEffectiveRole(effectiveRole);
-        return vo;
-    }
-
-    private AddFamilyMemberDTO mockAddDTO(String nickname, String generationLevel) {
-        AddFamilyMemberDTO dto = new AddFamilyMemberDTO();
-        dto.setNickname(nickname);
-        dto.setGenerationLevel(generationLevel);
-        dto.setRelativeMemberId(1L);
-        return dto;
-    }
-
-    // ==================== addMember ====================
-
-    @Test
-    public void addMember_Success() {
-        Long userId = 1L;
-        AddFamilyMemberDTO dto = mockAddDTO("小明", "child");
-
-        when(familyMemberService.addMember(eq(userId), any(AddFamilyMemberDTO.class)))
-            .thenReturn(mockMemberVO(100L, "小明", "child"));
-
-        Result<FamilyMemberVO> result = controller.addMember(dto, userId);
-        assertEquals(200, result.getCode());
-        assertEquals("小明", result.getData().getNickname());
-    }
-
-    @Test
-    public void addMember_NotLoggedIn() {
-        Long userId = null;
-        AddFamilyMemberDTO dto = mockAddDTO("小明", "child");
-
-        Result<FamilyMemberVO> result = controller.addMember(dto, userId);
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("请先登录"));
-    }
-
-    @Test
-    public void addMember_IllegalArgument() {
-        Long userId = 1L;
-        AddFamilyMemberDTO dto = mockAddDTO("", "");
-
-        when(familyMemberService.addMember(eq(userId), any(AddFamilyMemberDTO.class)))
-            .thenThrow(new IllegalArgumentException("辈分等级不能为空"));
-
-        Result<FamilyMemberVO> result = controller.addMember(dto, userId);
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("辈分等级不能为空"));
-    }
-
-    // ==================== listMembers ====================
-
-    @Test
-    public void listMembers_Success() {
-        Long userId = 1L;
-        List<FamilyMemberVO> members = Arrays.asList(
-            mockMemberVO(1L, "爸爸", "parent"),
-            mockMemberVO(2L, "妈妈", "parent")
-        );
-
-        when(familyMemberService.listMembers(userId)).thenReturn(members);
-
-        Result<List<FamilyMemberVO>> result = controller.listMembers(userId);
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().size());
-    }
-
-    @Test
-    public void listMembers_NotLoggedIn() {
-        Long userId = null;
-        Result<List<FamilyMemberVO>> result = controller.listMembers(userId);
-        assertEquals(500, result.getCode());
-    }
-
-    // ==================== switchToMember ====================
-
-    @Test
-    public void switchToMember_Success() {
-        Long userId = 1L;
-        Map<String, Object> body = new HashMap<>();
-        body.put("memberId", 2L);
-
-        SwitchMemberVO vo = new SwitchMemberVO();
-        vo.setMemberId(2L);
-        vo.setNickname("小明");
-        when(familyMemberService.switchToMember(userId, 2L)).thenReturn(vo);
-
-        Result<SwitchMemberVO> result = controller.switchToMember(body, userId);
-        assertEquals(200, result.getCode());
-        assertEquals(2L, result.getData().getMemberId().longValue());
-    }
-
-    @Test
-    public void switchToMember_MissingMemberId() {
-        Long userId = 1L;
-        Map<String, Object> body = new HashMap<>();
-
-        Result<SwitchMemberVO> result = controller.switchToMember(body, userId);
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("缺少成员ID"));
-    }
-
-    // ==================== kickMember ====================
-
-    @Test
-    public void kickMember_Success() {
-        Long userId = 1L;
-        Map<String, Long> body = new HashMap<>();
-        body.put("memberId", 3L);
-
-        doNothing().when(familyMemberService).kickMember(userId, 3L);
-
-        Result<String> result = controller.kickMember(body, userId);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData().contains("踢出成功"));
-    }
-
-    @Test
-    public void kickMember_MissingMemberId() {
-        Long userId = 1L;
-        Map<String, Long> body = new HashMap<>();
-
-        Result<String> result = controller.kickMember(body, userId);
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("缺少成员ID"));
-    }
-
-    // ==================== updateMember ====================
-
-    @Test
-    public void updateMember_Success() {
-        Long userId = 1L;
-        Map<String, Object> body = new HashMap<>();
-        body.put("memberId", 5L);
-        body.put("nickname", "新名字");
-
-        when(familyMemberService.updateMember(eq(userId), eq(5L), any(AddFamilyMemberDTO.class)))
-            .thenReturn(mockMemberVO(5L, "新名字", "parent"));
-
-        Result<FamilyMemberVO> result = controller.updateMember(body, userId);
-        assertEquals(200, result.getCode());
-        assertEquals("新名字", result.getData().getNickname());
-    }
-
-    @Test
-    public void updateMember_MissingMemberId() {
-        Long userId = 1L;
-        Map<String, Object> body = new HashMap<>();
-
-        Result<FamilyMemberVO> result = controller.updateMember(body, userId);
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("缺少成员ID"));
-    }
-
-}

+ 0 - 251
cfc-backend/src/test/java/com/etotem/cfc/integration/AdminArticleControllerTest.java

@@ -1,251 +0,0 @@
-package com.etotem.cfc.controller;
-
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.admin.AdminArticleController;
-import com.etotem.cfc.entity.Article;
-import com.etotem.cfc.entity.ArticleCategory;
-import com.etotem.cfc.service.ArticleCategoryService;
-import com.etotem.cfc.service.ArticleService;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-@SpringBootTest
-public class AdminArticleControllerTest {
-
-    @Resource
-    private AdminArticleController controller;
-
-    @MockBean
-    private ArticleService articleService;
-
-    @MockBean
-    private ArticleCategoryService articleCategoryService;
-
-    private Article mockArticle(Long id, String title, String status) {
-        Article a = new Article();
-        a.setId(id);
-        a.setTitle(title);
-        a.setSummary("摘要");
-        a.setContent("<p>内容</p>");
-        a.setAuthor("管理员");
-        a.setStatus(status);
-        a.setCategoryId(1L);
-        return a;
-    }
-
-    // ==================== list ====================
-
-    @Test
-    public void adminList_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("page", 1);
-        body.put("size", 20);
-
-        List<Article> records = Arrays.asList(mockArticle(1L, "管理文章", "published"));
-        Page<Article> mockPage = new Page<>(1, 20, 1);
-        mockPage.setRecords(records);
-
-        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
-            .thenReturn(mockPage);
-
-        Result<Page<Article>> result = controller.list(body);
-        assertEquals(200, result.getCode());
-        assertEquals(1, result.getData().getRecords().size());
-    }
-
-    @Test
-    public void adminList_WithFilters() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("status", "draft");
-        body.put("categoryId", 2);
-        body.put("keyword", "测试");
-        body.put("page", 1);
-        body.put("size", 10);
-
-        when(articleService.getAdminList(eq("draft"), eq(2L), eq("测试"), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(10)))
-            .thenReturn(new Page<>());
-
-        Result<Page<Article>> result = controller.list(body);
-        assertEquals(200, result.getCode());
-    }
-
-    @Test
-    public void adminList_DefaultPagination() {
-        Map<String, Object> body = new HashMap<>();
-
-        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
-            .thenReturn(new Page<>());
-
-        Result<Page<Article>> result = controller.list(body);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== create ====================
-
-    @Test
-    public void adminCreate_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("title", "新文章");
-        body.put("content", "内容");
-        body.put("status", "draft");
-
-        doNothing().when(articleService).create(any(Article.class), eq(1L));
-
-        Result<Map<String, Object>> result = controller.create(body, 1L);
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-    }
-
-    // ==================== update ====================
-
-    @Test
-    public void adminUpdate_Success() {
-Map<String, Object> body = new HashMap<>();
-        body.put("id", 1L);
-        body.put("title", "更新标题");
-        body.put("content", "内容");
-        body.put("status", "published");
-
-        doNothing().when(articleService).update(any(Article.class));
-
-        Result<String> result = controller.update(body);
-        assertEquals(200, result.getCode());
-        assertEquals("更新成功", result.getData());
-    }
-
-    // ==================== delete ====================
-
-    @Test
-    public void adminDelete_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        doNothing().when(articleService).delete(1L);
-
-        Result<String> result = controller.delete(body);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== publish ====================
-
-    @Test
-    public void adminPublish_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("status", "published");
-        doNothing().when(articleService).toggleStatus(1L, "published");
-
-        Result<String> result = controller.publish(body);
-        assertEquals(200, result.getCode());
-        assertEquals("操作成功", result.getData());
-    }
-
-    @Test
-    public void adminUnpublish_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("status", "draft");
-        doNothing().when(articleService).toggleStatus(1L, "draft");
-
-        Result<String> result = controller.publish(body);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== toggleFeatured ====================
-
-    @Test
-    public void adminToggleFeatured_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("isFeatured", 1);
-        doNothing().when(articleService).toggleFeatured(1L, 1);
-
-        Result<String> result = controller.toggleFeatured(body);
-        assertEquals(200, result.getCode());
-    }
-
-    @Test
-    public void adminToggleUnfeatured_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("isFeatured", 0);
-        doNothing().when(articleService).toggleFeatured(1L, 0);
-
-        Result<String> result = controller.toggleFeatured(body);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== category list ====================
-
-    @Test
-    public void adminCategoryList_Success() {
-        ArticleCategory cat = new ArticleCategory();
-        cat.setId(1L);
-        cat.setName("心理健康");
-        cat.setStatus(1);
-
-        when(articleCategoryService.listAll()).thenReturn(Arrays.asList(cat));
-
-        Result<List<ArticleCategory>> result = controller.categoryList();
-        assertEquals(200, result.getCode());
-        assertEquals(1, result.getData().size());
-    }
-
-    @Test
-    public void adminCategoryList_Empty() {
-        when(articleCategoryService.listAll()).thenReturn(Collections.emptyList());
-
-        Result<List<ArticleCategory>> result = controller.categoryList();
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData().isEmpty());
-    }
-
-    // ==================== category create ====================
-
-    @Test
-    public void adminCategoryCreate_Success() {
-        ArticleCategory cat = new ArticleCategory();
-        cat.setName("新分类");
-
-        doNothing().when(articleCategoryService).create(cat);
-
-        Result<String> result = controller.categoryCreate(cat);
-        assertEquals(200, result.getCode());
-        assertEquals("创建成功", result.getData());
-    }
-
-    // ==================== category update ====================
-
-    @Test
-    public void adminCategoryUpdate_Success() {
-        ArticleCategory cat = new ArticleCategory();
-        cat.setId(1L);
-        cat.setName("更新分类");
-
-        doNothing().when(articleCategoryService).update(cat);
-
-        Result<String> result = controller.categoryUpdate(cat);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== category delete ====================
-
-    @Test
-    public void adminCategoryDelete_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-
-        doNothing().when(articleCategoryService).delete(1L);
-
-        Result<String> result = controller.categoryDelete(body);
-        assertEquals(200, result.getCode());
-    }
-}

+ 0 - 286
cfc-backend/src/test/java/com/etotem/cfc/integration/ArticleAdminControllerTest.java

@@ -1,286 +0,0 @@
-package com.etotem.cfc.controller;
-
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.admin.AdminArticleController;
-import com.etotem.cfc.entity.Article;
-import com.etotem.cfc.entity.ArticleCategory;
-import com.etotem.cfc.service.ArticleCategoryService;
-import com.etotem.cfc.service.ArticleService;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-/**
- * 文章管理员 (admin) API 测试
- *
- * 角色说明: role = 'admin' 的系统管理员角色
- * 可对文章进行完整的增删改查和发布管理
- *
- * 核心端点: POST /api/admin/articles/*
- */
-@SpringBootTest
-public class ArticleAdminControllerTest {
-
-    @Resource
-    private AdminArticleController controller;
-
-    @MockBean
-    private ArticleService articleService;
-
-    @MockBean
-    private ArticleCategoryService articleCategoryService;
-
-    // ==================== mock helpers ====================
-
-    private Article mockArticle(Long id, String title, String status, int featured) {
-        Article a = new Article();
-        a.setId(id);
-        a.setTitle(title);
-        a.setSummary("文章摘要");
-        a.setContent("<p>正文内容</p>");
-        a.setCoverImage("http://example.com/cover.jpg");
-        a.setAuthor("管理员");
-        a.setStatus(status);   // draft/published
-        a.setIsFeatured(featured); // 0/1
-        a.setCategoryId(1L);
-        a.setViewCount(100);
-        a.setReadTime(5);
-        a.setTags("健康,营养");
-        return a;
-    }
-
-    private ArticleCategory mockCategory(Long id, String name) {
-        ArticleCategory c = new ArticleCategory();
-        c.setId(id);
-        c.setName(name);
-        c.setSortOrder(1);
-        return c;
-    }
-
-    // ==================== list ====================
-
-    @Test
-    public void list_AllArticles() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("page", 1);
-        body.put("size", 20);
-
-        List<Article> records = Arrays.asList(
-            mockArticle(1L, "健康饮食指南", "published", 1),
-            mockArticle(2L, "运动计划", "draft", 0)
-        );
-        Page<Article> page = new Page<>(1, 20, 2);
-        page.setRecords(records);
-
-        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
-            .thenReturn(page);
-
-        Result<Page<Article>> result = controller.list(body);
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().getRecords().size());
-    }
-
-    @Test
-    public void list_WithFilters() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("status", "published");
-        body.put("categoryId", 2);
-        body.put("keyword", "健康");
-        body.put("page", 1);
-        body.put("size", 10);
-
-        List<Article> records = Collections.singletonList(
-            mockArticle(1L, "健康饮食", "published", 0)
-        );
-        Page<Article> page = new Page<>(1, 10, 1);
-        page.setRecords(records);
-
-        when(articleService.getAdminList(eq("published"), eq(2L), eq("健康"), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(10)))
-            .thenReturn(page);
-
-        Result<Page<Article>> result = controller.list(body);
-        assertEquals(200, result.getCode());
-        assertEquals(1, result.getData().getRecords().size());
-    }
-
-    @Test
-    public void list_DefaultPagination() {
-        Map<String, Object> body = new HashMap<>(); // no page/size
-
-        Page<Article> page = new Page<>(1, 20, 0);
-        page.setRecords(Collections.emptyList());
-
-        when(articleService.getAdminList(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), eq(1), eq(20)))
-            .thenReturn(page);
-
-        Result<Page<Article>> result = controller.list(body);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== create ====================
-
-    @Test
-    public void create_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("title", "新文章");
-        body.put("content", "内容");
-        body.put("status", "draft");
-
-        doNothing().when(articleService).create(any(Article.class), eq(1L));
-
-        Result<Map<String, Object>> result = controller.create(body, 1L);
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        verify(articleService).create(any(Article.class), eq(1L));
-    }
-
-    // ==================== update ====================
-
-    @Test
-    public void update_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1L);
-        body.put("title", "更新后的文章");
-        body.put("content", "新内容");
-        body.put("status", "published");
-
-        doNothing().when(articleService).update(any(Article.class));
-
-        Result<String> result = controller.update(body);
-        assertEquals(200, result.getCode());
-        assertEquals("更新成功", result.getData());
-        verify(articleService).update(any(Article.class));
-    }
-
-    // ==================== delete ====================
-
-    @Test
-    public void delete_Success() {
-        doNothing().when(articleService).delete(1L);
-
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-
-        Result<String> result = controller.delete(body);
-        assertEquals(200, result.getCode());
-        assertEquals("删除成功", result.getData());
-        verify(articleService).delete(1L);
-    }
-
-    // ==================== publish ====================
-
-    @Test
-    public void publish_Success() {
-        doNothing().when(articleService).toggleStatus(1L, "published");
-
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("status", "published");
-
-        Result<String> result = controller.publish(body);
-        assertEquals(200, result.getCode());
-        assertEquals("操作成功", result.getData());
-        verify(articleService).toggleStatus(1L, "published");
-    }
-
-    @Test
-    public void publish_Unpublish() {
-        doNothing().when(articleService).toggleStatus(1L, "draft");
-
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("status", "draft");
-
-        Result<String> result = controller.publish(body);
-        assertEquals(200, result.getCode());
-        verify(articleService).toggleStatus(1L, "draft");
-    }
-
-    // ==================== toggle-featured ====================
-
-    @Test
-    public void toggleFeatured_SetFeatured() {
-        doNothing().when(articleService).toggleFeatured(1L, 1);
-
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("isFeatured", 1);
-
-        Result<String> result = controller.toggleFeatured(body);
-        assertEquals(200, result.getCode());
-        verify(articleService).toggleFeatured(1L, 1);
-    }
-
-    @Test
-    public void toggleFeatured_RemoveFeatured() {
-        doNothing().when(articleService).toggleFeatured(1L, 0);
-
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-        body.put("isFeatured", 0);
-
-        Result<String> result = controller.toggleFeatured(body);
-        assertEquals(200, result.getCode());
-        verify(articleService).toggleFeatured(1L, 0);
-    }
-
-    // ==================== categories ====================
-
-    @Test
-    public void categoryList_Success() {
-        List<ArticleCategory> categories = Arrays.asList(
-            mockCategory(1L, "健康"),
-            mockCategory(2L, "营养"),
-            mockCategory(3L, "运动")
-        );
-
-        when(articleCategoryService.listAll()).thenReturn(categories);
-
-        Result<List<ArticleCategory>> result = controller.categoryList();
-        assertEquals(200, result.getCode());
-        assertEquals(3, result.getData().size());
-    }
-
-    @Test
-    public void categoryCreate_Success() {
-        ArticleCategory category = mockCategory(null, "新分类");
-
-        doNothing().when(articleCategoryService).create(any(ArticleCategory.class));
-
-        Result<String> result = controller.categoryCreate(category);
-        assertEquals(200, result.getCode());
-        assertEquals("创建成功", result.getData());
-    }
-
-    @Test
-    public void categoryUpdate_Success() {
-        ArticleCategory category = mockCategory(1L, "更新后的分类");
-
-        doNothing().when(articleCategoryService).update(any(ArticleCategory.class));
-
-        Result<String> result = controller.categoryUpdate(category);
-        assertEquals(200, result.getCode());
-        assertEquals("更新成功", result.getData());
-    }
-
-    @Test
-    public void categoryDelete_Success() {
-        doNothing().when(articleCategoryService).delete(1L);
-
-        Map<String, Object> body = new HashMap<>();
-        body.put("id", 1);
-
-        Result<String> result = controller.categoryDelete(body);
-        assertEquals(200, result.getCode());
-        assertEquals("删除成功", result.getData());
-        verify(articleCategoryService).delete(1L);
-    }
-}

+ 0 - 327
cfc-backend/src/test/java/com/etotem/cfc/integration/ArticleServiceTest.java

@@ -1,327 +0,0 @@
-package com.etotem.cfc.service;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.etotem.cfc.entity.Article;
-import com.etotem.cfc.mapper.ArticleMapper;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-@SpringBootTest
-public class ArticleServiceTest {
-
-    @Resource
-    private ArticleService articleService;
-
-    @MockBean
-    private ArticleMapper articleMapper;
-
-    @MockBean
-    private ArticlePermissionService articlePermissionService;
-
-    @MockBean
-    private ArticleCategoryService articleCategoryService;
-
-    private Article mockArticle(Long id, String title, String status, String visibility) {
-        Article a = new Article();
-        a.setId(id);
-        a.setTitle(title);
-        a.setSummary("摘要");
-        a.setContent("<p>内容</p>");
-        a.setAuthor("测试");
-        a.setStatus(status);
-        a.setVisibility(visibility);
-        a.setCategoryId(1L);
-        a.setIsFeatured(0);
-        a.setViewCount(5);
-        a.setCreatedBy(1L);
-        return a;
-    }
-
-    // ==================== getPublicList ====================
-
-    @Test
-    public void getPublicList_OnlyPublished() {
-        List<Article> allArticles = Arrays.asList(
-            mockArticle(1L, "已发布", "published", "public"),
-            mockArticle(2L, "草稿", "draft", "public")
-        );
-
-        // Mock mapper to return all articles (real filtering happens via wrapper)
-        when(articleMapper.selectPage(any(Page.class), any(LambdaQueryWrapper.class)))
-            .thenAnswer(invocation -> {
-                Page<Article> page = invocation.getArgument(0);
-                page.setRecords(allArticles);
-                page.setTotal(2);
-                return page;
-            });
-
-        // Permission service allows all visible ones
-        when(articlePermissionService.filterVisible(anyList(), isNull(), isNull(), isNull()))
-            .thenReturn(Arrays.asList(allArticles.get(0))); // Only published
-
-        Page<Article> result = articleService.getPublicList(null, null, null, 1, 10, null, null, null);
-        assertEquals(1, result.getRecords().size());
-        assertEquals("已发布", result.getRecords().get(0).getTitle());
-    }
-
-    @Test
-    public void getPublicList_Empty() {
-        when(articleMapper.selectPage(any(Page.class), any(LambdaQueryWrapper.class)))
-            .thenAnswer(invocation -> {
-                Page<Article> page = invocation.getArgument(0);
-                page.setRecords(Collections.emptyList());
-                page.setTotal(0);
-                return page;
-            });
-        when(articlePermissionService.filterVisible(anyList(), isNull(), isNull(), isNull()))
-            .thenReturn(Collections.emptyList());
-
-        Page<Article> result = articleService.getPublicList(null, null, null, 1, 10, null, null, null);
-        assertTrue(result.getRecords().isEmpty());
-        assertEquals(0, result.getTotal());
-    }
-
-    // ==================== getDetail ====================
-
-    @Test
-    public void getDetail_Success() {
-        Article article = mockArticle(1L, "详情文章", "published", "public");
-        when(articleMapper.selectById(1L)).thenReturn(article);
-        when(articlePermissionService.isVisible(article, null, null, null)).thenReturn(true);
-
-        Article result = articleService.getDetail(1L, null, null, null);
-        assertNotNull(result);
-        assertEquals("详情文章", result.getTitle());
-    }
-
-    @Test
-    public void getDetail_NotFound() {
-        when(articleMapper.selectById(999L)).thenReturn(null);
-
-        Article result = articleService.getDetail(999L, null, null, null);
-        assertNull(result);
-    }
-
-    @Test
-    public void getDetail_NotPublished() {
-        Article article = mockArticle(1L, "草稿", "draft", "public");
-        when(articleMapper.selectById(1L)).thenReturn(article);
-
-        Article result = articleService.getDetail(1L, null, null, null);
-        assertNull(result);
-    }
-
-    @Test
-    public void getDetail_NoPermission() {
-        Article article = mockArticle(1L, "私密文章", "published", "private");
-        when(articleMapper.selectById(1L)).thenReturn(article);
-        when(articlePermissionService.isVisible(article, null, null, null)).thenReturn(false);
-
-        Article result = articleService.getDetail(1L, null, null, null);
-        assertNull(result);
-    }
-
-    // ==================== getFeatured ====================
-
-    @Test
-    public void getFeatured_Success() {
-        List<Article> featured = Arrays.asList(
-            mockArticle(1L, "精选1", "published", "public"),
-            mockArticle(2L, "精选2", "published", "public")
-        );
-
-        when(articleMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(featured);
-        when(articlePermissionService.filterVisible(featured, null, null, null)).thenReturn(featured);
-
-        List<Article> result = articleService.getFeatured(5, null, null, null);
-        assertEquals(2, result.size());
-    }
-
-    @Test
-    public void getFeatured_Limit() {
-        List<Article> featured = Arrays.asList(
-            mockArticle(1L, "精选1", "published", "public"),
-            mockArticle(2L, "精选2", "published", "public"),
-            mockArticle(3L, "精选3", "published", "public")
-        );
-
-        when(articleMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(featured);
-        when(articlePermissionService.filterVisible(featured, null, null, null)).thenReturn(featured);
-
-        List<Article> result = articleService.getFeatured(2, null, null, null);
-        assertEquals(2, result.size());
-    }
-
-    @Test
-    public void getFeatured_Empty() {
-        when(articleMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(Collections.emptyList());
-        when(articlePermissionService.filterVisible(anyList(), isNull(), isNull(), isNull()))
-            .thenReturn(Collections.emptyList());
-
-        List<Article> result = articleService.getFeatured(5, null, null, null);
-        assertTrue(result.isEmpty());
-    }
-
-    // ==================== recordRead ====================
-
-    @Test
-    public void recordRead_IncrementsViewCount() {
-        doAnswer(invocation -> {
-            // Verify the update wrapper has setSql for view_count increment
-            return 1;
-        }).when(articleMapper).update(any(), any(LambdaQueryWrapper.class));
-
-        articleService.recordRead(1L, null, null, 30);
-        verify(articleMapper, times(1)).update(any(), any());
-    }
-
-    // ==================== getAdminList ====================
-
-    @Test
-    public void getAdminList_All() {
-        when(articleMapper.selectPage(any(Page.class), any(LambdaQueryWrapper.class)))
-            .thenAnswer(invocation -> {
-                Page<Article> page = invocation.getArgument(0);
-                page.setRecords(Arrays.asList(mockArticle(1L, "管理可见", "published", "public")));
-                page.setTotal(1);
-                return page;
-            });
-
-        Page<Article> result = articleService.getAdminList(null, null, null, null, null, null, null, null, 1, 20);
-        assertEquals(1, result.getRecords().size());
-    }
-
-    @Test
-    public void getAdminList_WithStatusFilter() {
-        when(articleMapper.selectPage(any(Page.class), any(LambdaQueryWrapper.class)))
-            .thenAnswer(invocation -> {
-                Page<Article> page = invocation.getArgument(0);
-                page.setRecords(Arrays.asList(mockArticle(1L, "草稿文章", "draft", "public")));
-                page.setTotal(1);
-                return page;
-            });
-
-        Page<Article> result = articleService.getAdminList("draft", null, null, null, null, null, null, null, 1, 20);
-        assertEquals(1, result.getRecords().size());
-    }
-
-    // ==================== create ====================
-
-    @Test
-    public void create_SetsInitialValues() {
-        Article article = mockArticle(null, "新文章", "draft", "public");
-        when(articleMapper.insert(any(Article.class))).thenReturn(1);
-
-        articleService.create(article, 1L);
-
-        verify(articleMapper).insert(argThat(a -> {
-            assertNull(a.getId());
-            assertEquals(1L, a.getCreatedBy().longValue());
-            assertEquals(0, a.getViewCount().intValue());
-            assertNotNull(a.getCreatedAt());
-            assertNotNull(a.getUpdatedAt());
-            return true;
-        }));
-    }
-
-    @Test
-    public void create_PublishedSetsPublishTime() {
-        Article article = mockArticle(null, "直接发布", "published", "public");
-        when(articleMapper.insert(any(Article.class))).thenReturn(1);
-
-        articleService.create(article, 1L);
-
-        verify(articleMapper).insert(argThat(a -> {
-            assertNotNull(a.getPublishedAt());
-            return true;
-        }));
-    }
-
-    // ==================== update ====================
-
-    @Test
-    public void update_SetsUpdatedAt() {
-        Article article = mockArticle(1L, "更新", "published", "public");
-        when(articleMapper.updateById(any(Article.class))).thenReturn(1);
-
-        articleService.update(article);
-        verify(articleMapper).updateById(argThat(a -> {
-            assertNotNull(a.getUpdatedAt());
-            return true;
-        }));
-    }
-
-    // ==================== delete ====================
-
-    @Test
-    public void delete_DeletesById() {
-        articleService.delete(1L);
-        verify(articleMapper).deleteById(1L);
-    }
-
-    // ==================== toggleStatus ====================
-
-    @Test
-    public void toggleStatus_Publish() {
-        Article article = mockArticle(1L, "发布", "draft", "public");
-        when(articleMapper.selectById(1L)).thenReturn(article);
-        when(articleMapper.updateById(any(Article.class))).thenReturn(1);
-
-        articleService.toggleStatus(1L, "published");
-        assertEquals("published", article.getStatus());
-        assertNotNull(article.getUpdatedAt());
-        assertNotNull(article.getPublishedAt());
-    }
-
-    @Test
-    public void toggleStatus_Draft() {
-        Article article = mockArticle(1L, "下架", "published", "public");
-        article.setPublishedAt(new Date());
-        when(articleMapper.selectById(1L)).thenReturn(article);
-        when(articleMapper.updateById(any(Article.class))).thenReturn(1);
-
-        articleService.toggleStatus(1L, "draft");
-        assertEquals("draft", article.getStatus());
-    }
-
-    @Test
-    public void toggleStatus_ArticleNotFound() {
-        when(articleMapper.selectById(999L)).thenReturn(null);
-
-        articleService.toggleStatus(999L, "published");
-        verify(articleMapper, never()).updateById(any());
-    }
-
-    // ==================== toggleFeatured ====================
-
-    @Test
-    public void toggleFeatured_SetFeatured() {
-        Article article = mockArticle(1L, "精选", "published", "public");
-        when(articleMapper.selectById(1L)).thenReturn(article);
-
-        articleService.toggleFeatured(1L, 1);
-        assertEquals(1, article.getIsFeatured().intValue());
-        assertNotNull(article.getUpdatedAt());
-        verify(articleMapper).updateById(article);
-    }
-
-    @Test
-    public void toggleFeatured_RemoveFeatured() {
-        Article article = mockArticle(1L, "取消精选", "published", "public");
-        article.setIsFeatured(1);
-        when(articleMapper.selectById(1L)).thenReturn(article);
-
-        articleService.toggleFeatured(1L, 0);
-        assertEquals(0, article.getIsFeatured().intValue());
-        verify(articleMapper).updateById(article);
-    }
-}

+ 0 - 381
cfc-backend/src/test/java/com/etotem/cfc/integration/EnergyControllerTest.java

@@ -1,381 +0,0 @@
-package com.etotem.cfc.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.EnergyController;
-import com.etotem.cfc.dto.EnergySandboxDTO;
-import com.etotem.cfc.dto.MemberEnergyDTO;
-import com.etotem.cfc.entity.EnergyLog;
-import com.etotem.cfc.entity.User;
-import com.etotem.cfc.mapper.UserMapper;
-import com.etotem.cfc.service.EnergyService;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-/**
- * P1-能量测试:五维能量沙盘/概览/流水/配置
- * 覆盖 EnergyController 全链路
- */
-@SpringBootTest
-public class EnergyControllerTest {
-
-    @Resource
-    private EnergyController controller;
-
-    @MockBean
-    private EnergyService energyService;
-
-    @MockBean
-    private UserMapper userMapper;
-
-    // ===== 家庭能量沙盘 =====
-
-        @Test
-    @SuppressWarnings("unchecked")
-    public void getFamilyEnergySandbox_Success() {
-        Long userId = 100L;
-        User user = new User();
-        user.setId(userId);
-        user.setFamilyId(100L);
-        when(userMapper.selectById(userId)).thenReturn(user);
-
-        Map<String, Object> mockData = new HashMap<>();
-        mockData.put("overallScore", 850);
-        mockData.put("bodyScore", 180);
-        mockData.put("mindScore", 160);
-        mockData.put("wisdomScore", 150);
-        mockData.put("actionScore", 200);
-        mockData.put("wealthScore", 160);
-        mockData.put("members", java.util.Collections.emptyList());
-
-        when(energyService.calculateFamilyEnergy(100L)).thenReturn(mockData);
-
-        Result<?> result = controller.getFamilyEnergySandbox(userId, null);
-
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-    }
-    @Test
-    public void getFamilyEnergySandbox_UserNotFound() {
-        when(userMapper.selectById(999L)).thenReturn(null);
-
-        Result<?> result = controller.getFamilyEnergySandbox(999L, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("用户不存在", result.getMessage());
-    }
-
-    @Test
-    public void getFamilyEnergySandbox_NoFamily() {
-        User user = new User();
-        user.setId(1L);
-        user.setFamilyId(null);
-
-        when(userMapper.selectById(1L)).thenReturn(user);
-
-        Result<?> result = controller.getFamilyEnergySandbox(1L, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("用户未加入家庭", result.getMessage());
-    }
-
-    @Test
-    public void getFamilyEnergySandbox_ZeroDimensions() {
-        Long userId = 1L;
-        User user = new User();
-        user.setId(userId);
-        user.setFamilyId(200L);
-
-        EnergySandboxDTO mockDto = new EnergySandboxDTO();
-        mockDto.setBodyScore(0);
-        mockDto.setMindScore(0);
-        mockDto.setWisdomScore(0);
-        mockDto.setActionScore(0);
-        mockDto.setWealthScore(0);
-        mockDto.setOverallScore(0);
-
-        when(userMapper.selectById(userId)).thenReturn(user);
-        when(energyService.calculateFamilyEnergy(200L)).thenReturn(mockDto);
-
-        Result<?> result = controller.getFamilyEnergySandbox(userId, null);
-
-        assertEquals(200, result.getCode());
-    }
-
-    // ===== 五维能量概览 =====
-
-    @Test
-    public void getEnergyOverview_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-
-        Map<String, Object> mockOverview = new LinkedHashMap<>();
-        mockOverview.put("childId", 10L);
-        mockOverview.put("childName", "小明");
-        mockOverview.put("totalEnergy", 850);
-        mockOverview.put("bodyScore", 180);
-        mockOverview.put("mindScore", 160);
-        mockOverview.put("wisdomScore", 150);
-        mockOverview.put("actionScore", 200);
-        mockOverview.put("wealthScore", 160);
-
-        when(energyService.getOverview(10L)).thenReturn(mockOverview);
-
-        Result<Map<String, Object>> result = controller.getEnergyOverview(params, 10L, null);
-
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(10L, result.getData().get("childId"));
-        assertEquals("小明", result.getData().get("childName"));
-        assertEquals(850, result.getData().get("totalEnergy"));
-        assertEquals(180, result.getData().get("bodyScore"));
-        assertEquals(160, result.getData().get("mindScore"));
-        assertEquals(150, result.getData().get("wisdomScore"));
-        assertEquals(200, result.getData().get("actionScore"));
-        assertEquals(160, result.getData().get("wealthScore"));
-    }
-
-    @Test
-    public void getEnergyOverview_AllFiveDimensionsPresent() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 20L);
-
-        Map<String, Object> mockOverview = new HashMap<>();
-        mockOverview.put("childId", 20L);
-        mockOverview.put("bodyScore", 100);
-        mockOverview.put("mindScore", 100);
-        mockOverview.put("wisdomScore", 100);
-        mockOverview.put("actionScore", 100);
-        mockOverview.put("wealthScore", 100);
-        mockOverview.put("totalEnergy", 500);
-
-        when(energyService.getOverview(20L)).thenReturn(mockOverview);
-
-        Result<Map<String, Object>> result = controller.getEnergyOverview(params, 20L, null);
-
-        assertEquals(200, result.getCode());
-        assertEquals(100, result.getData().get("bodyScore"));
-        assertEquals(100, result.getData().get("mindScore"));
-        assertEquals(100, result.getData().get("wisdomScore"));
-        assertEquals(100, result.getData().get("actionScore"));
-        assertEquals(100, result.getData().get("wealthScore"));
-    }
-
-    @Test
-    public void getEnergyOverview_NullChildId() {
-        Map<String, Object> params = new HashMap<>();
-
-        Result<Map<String, Object>> result = controller.getEnergyOverview(params, null, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("childId不能为空", result.getMessage());
-    }
-
-    @Test
-    public void getEnergyOverview_ZeroScore() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 30L);
-
-        Map<String, Object> mockOverview = new HashMap<>();
-        mockOverview.put("childId", 30L);
-        mockOverview.put("totalEnergy", 0);
-
-        when(energyService.getOverview(30L)).thenReturn(mockOverview);
-
-        Result<Map<String, Object>> result = controller.getEnergyOverview(params, 30L, null);
-
-        assertEquals(200, result.getCode());
-        assertEquals(0, result.getData().get("totalEnergy"));
-    }
-
-    // ===== 能量流水 =====
-
-    @Test
-    public void getEnergyLogs_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        params.put("page", 1);
-        params.put("size", 10);
-
-        List<EnergyLog> logs = Arrays.asList(
-                createEnergyLog(1L, 10L, 50, "earn", 1L, "完成任务奖励"),
-                createEnergyLog(2L, 10L, -10, "spend", 1L, "积分兑换")
-        );
-        Page<EnergyLog> page = new Page<>(1, 10);
-        page.setRecords(logs);
-        page.setTotal(2);
-
-        when(energyService.getLogs(10L, null, 1, 10)).thenReturn(page);
-
-        Result<Page<EnergyLog>> result = controller.getEnergyLogs(params, 10L, null);
-
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(2, result.getData().getRecords().size());
-    }
-
-    @Test
-    public void getEnergyLogs_FilterByDimension() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        params.put("dimensionCode", "body");
-        params.put("page", 1);
-        params.put("size", 10);
-
-        List<EnergyLog> logs = Collections.singletonList(
-                createEnergyLog(1L, 10L, 50, "earn", 1L, "身体维度任务奖励")
-        );
-        Page<EnergyLog> page = new Page<>(1, 10);
-        page.setRecords(logs);
-        page.setTotal(1);
-
-        when(energyService.getLogs(10L, "body", 1, 10)).thenReturn(page);
-
-        Result<Page<EnergyLog>> result = controller.getEnergyLogs(params, 10L, null);
-
-        assertEquals(200, result.getCode());
-        assertEquals(1, result.getData().getTotal());
-    }
-
-    @Test
-    public void getEnergyLogs_DefaultPagination() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        // page and size not provided
-
-        Page<EnergyLog> emptyPage = new Page<>(1, 10);
-        emptyPage.setRecords(Collections.emptyList());
-        emptyPage.setTotal(0);
-
-        when(energyService.getLogs(10L, null, 1, 10)).thenReturn(emptyPage);
-
-        Result<Page<EnergyLog>> result = controller.getEnergyLogs(params, 10L, null);
-
-        assertEquals(200, result.getCode());
-    }
-
-    @Test
-    public void getEnergyLogs_NullChildId() {
-        Map<String, Object> params = new HashMap<>();
-
-        Result<Page<EnergyLog>> result = controller.getEnergyLogs(params, null, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("childId不能为空", result.getMessage());
-    }
-
-    @Test
-    public void getEnergyLogs_EmptyResult() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 99L);
-        params.put("page", 1);
-        params.put("size", 10);
-
-        Page<EnergyLog> emptyPage = new Page<>(1, 10);
-        emptyPage.setRecords(Collections.emptyList());
-        emptyPage.setTotal(0);
-
-        when(energyService.getLogs(99L, null, 1, 10)).thenReturn(emptyPage);
-
-        Result<Page<EnergyLog>> result = controller.getEnergyLogs(params, 99L, null);
-
-        assertEquals(200, result.getCode());
-        assertEquals(0, result.getData().getTotal());
-    }
-
-    // ===== 配置来源比例 =====
-
-    @Test
-    public void configureSourceRatios_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("sourceType", "task");
-        params.put("sourceId", 5L);
-        params.put("sourceName", "每日任务");
-        params.put("ratios", Arrays.asList(
-                new HashMap<String, Object>() {{ put("dimension", "body"); put("ratio", 0.2); }},
-                new HashMap<String, Object>() {{ put("dimension", "mind"); put("ratio", 0.3); }},
-                new HashMap<String, Object>() {{ put("dimension", "wisdom"); put("ratio", 0.2); }},
-                new HashMap<String, Object>() {{ put("dimension", "action"); put("ratio", 0.2); }},
-                new HashMap<String, Object>() {{ put("dimension", "wealth"); put("ratio", 0.1); }}
-        ));
-
-        Result<String> result = controller.configureSourceRatios(params, 1L, null);
-
-        assertEquals(200, result.getCode());
-        assertEquals("配置成功", result.getData());
-        verify(energyService).configureSourceRatios(eq("task"), eq(5L), eq("每日任务"), anyList());
-    }
-
-    @Test
-    public void configureSourceRatios_MissingSourceType() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("sourceId", 5L);
-        params.put("ratios", Collections.emptyList());
-
-        Result<String> result = controller.configureSourceRatios(params, 1L, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("sourceType和sourceId不能为空", result.getMessage());
-    }
-
-    @Test
-    public void configureSourceRatios_EmptyRatios() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("sourceType", "task");
-        params.put("sourceId", 5L);
-        params.put("ratios", Collections.emptyList());
-
-        Result<String> result = controller.configureSourceRatios(params, 1L, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("ratios不能为空", result.getMessage());
-    }
-
-    @Test
-    public void configureSourceRatios_NullRatios() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("sourceType", "game");
-        params.put("sourceId", 3L);
-        // ratios not provided
-
-        Result<String> result = controller.configureSourceRatios(params, 1L, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("ratios不能为空", result.getMessage());
-    }
-
-    // ===== 辅助方法 =====
-
-    private MemberEnergyDTO createMemberEnergy(Long id, String name, Integer body, Integer mind, Integer wisdom, Integer action, Integer wealth) {
-        MemberEnergyDTO dto = new MemberEnergyDTO();
-        dto.setMemberId(id);
-        dto.setName(name);
-        dto.setBodyScore(body);
-        dto.setMindScore(mind);
-        dto.setWisdomScore(wisdom);
-        dto.setActionScore(action);
-        dto.setWealthScore(wealth);
-        dto.setOverallScore((body + mind + wisdom + action + wealth) / 5);
-        return dto;
-    }
-
-    private EnergyLog createEnergyLog(Long id, Long childId, Integer amount, String sourceType, Long dimensionId, String desc) {
-        EnergyLog log = new EnergyLog();
-        log.setId(id);
-        log.setChildId(childId);
-        log.setAmount(amount);
-        log.setSourceType(sourceType);
-        log.setDimensionId(dimensionId);
-        log.setDescription(desc);
-        log.setCreatedAt(new Date());
-        return log;
-    }
-}

+ 0 - 270
cfc-backend/src/test/java/com/etotem/cfc/integration/FamilyChallengeServiceTest.java

@@ -1,270 +0,0 @@
-package com.etotem.cfc.service;
-
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.entity.FamilyChallenge;
-import com.etotem.cfc.entity.FamilyChallengeParticipant;
-import com.etotem.cfc.entity.FamilyChallengeProgress;
-import com.etotem.cfc.entity.FamilyMember;
-import com.etotem.cfc.mapper.FamilyChallengeMapper;
-import com.etotem.cfc.mapper.FamilyChallengeParticipantMapper;
-import com.etotem.cfc.mapper.FamilyChallengeProgressMapper;
-import com.etotem.cfc.mapper.FamilyMemberMapper;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Date;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyList;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class FamilyChallengeServiceTest {
-
-    @Mock private FamilyChallengeMapper familyChallengeMapper;
-    @Mock private FamilyChallengeProgressMapper familyChallengeProgressMapper;
-    @Mock private FamilyChallengeParticipantMapper familyChallengeParticipantMapper;
-    @Mock private FamilyMemberMapper familyMemberMapper;
-    @Mock private HealthScoreService healthScoreService;
-    @Mock private PointsService pointsService;
-    @Mock private ChallengeScoreService challengeScoreService;
-    @InjectMocks private FamilyChallengeService service;
-
-    @BeforeEach
-    void setUp() {
-        MockitoAnnotations.openMocks(this);
-        when(familyChallengeParticipantMapper.selectList(any())).thenReturn(java.util.Collections.emptyList());
-    }
-
-    @Test
-    void updateProgress_shouldRejectDuplicateCheckinSameDay() {
-        FamilyChallenge challenge = new FamilyChallenge();
-        challenge.setId(1L);
-        challenge.setFamilyId(10L);
-        challenge.setStatus("active");
-        challenge.setTargetMode("aggregate");
-        challenge.setTargetValue(300);
-        challenge.setEndDate(new Date(System.currentTimeMillis() + 86400000L * 7));
-
-        FamilyChallengeProgress existing = new FamilyChallengeProgress();
-        existing.setChallengeId(1L);
-        existing.setChildId(100L);
-        existing.setProgressValue(5);
-        existing.setUpdatedAt(new Date());
-
-        FamilyChallengeParticipant participant = new FamilyChallengeParticipant();
-        participant.setChallengeId(1L);
-        participant.setMemberId(100L);
-        participant.setStatus("agreed");
-
-        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
-        when(familyChallengeProgressMapper.selectOne(any())).thenReturn(existing);
-        when(familyMemberMapper.selectCount(any())).thenReturn(1L);
-        when(familyChallengeParticipantMapper.selectOne(any())).thenReturn(participant);
-
-        Result<Void> result = service.updateProgress(1L, 100L, 1);
-
-        assertEquals(Integer.valueOf(500), result.getCode());
-        verify(familyChallengeProgressMapper, never()).updateById(any());
-    }
-
-    @Test
-    void updateProgress_shouldRejectWhenChallengeNotActive() {
-        FamilyChallenge challenge = new FamilyChallenge();
-        challenge.setId(1L);
-        challenge.setFamilyId(10L);
-        challenge.setStatus("completed");
-        challenge.setTargetMode("aggregate");
-        challenge.setTargetValue(300);
-        challenge.setEndDate(new Date(System.currentTimeMillis() + 86400000L * 7));
-
-        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
-
-        Result<Void> result = service.updateProgress(1L, 100L, 1);
-
-        assertEquals(Integer.valueOf(500), result.getCode());
-        verify(familyChallengeProgressMapper, never()).insert(any());
-        verify(familyChallengeProgressMapper, never()).updateById(any());
-    }
-
-    @Test
-    void checkAndSettle_shouldGrantPointsWhenCompleted() {
-        FamilyChallenge challenge = new FamilyChallenge();
-        challenge.setId(1L);
-        challenge.setFamilyId(10L);
-        challenge.setStatus("active");
-        challenge.setTargetMode("aggregate");
-        challenge.setTargetValue(10);
-        challenge.setRewardPoints(50);
-        challenge.setEndDate(new Date(System.currentTimeMillis() - 86400000L));
-
-        FamilyChallengeProgress p = new FamilyChallengeProgress();
-        p.setChallengeId(1L);
-        p.setChildId(100L);
-        p.setProgressValue(12);
-        p.setCompleted(false);
-
-        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
-        when(familyChallengeProgressMapper.selectList(any())).thenReturn(java.util.Arrays.asList(p));
-        when(familyMemberMapper.selectList(any())).thenReturn(java.util.Collections.emptyList());
-        when(familyChallengeMapper.update(any(), any())).thenReturn(1);
-
-        service.settleChallenge(1L);
-
-        verify(familyChallengeMapper).update(any(), any());
-        verify(familyChallengeProgressMapper).updateById(argThat(p2 -> Boolean.TRUE.equals(p2.getCompleted())));
-        verify(pointsService).awardSystemPoints(eq(100L), eq(50), anyString());
-    }
-
-    @Test
-    void getActiveChallenges_shouldSettleExpiredChallenges() {
-        FamilyChallenge expired = new FamilyChallenge();
-        expired.setId(2L);
-        expired.setFamilyId(10L);
-        expired.setStatus("active");
-        expired.setTargetMode("aggregate");
-        expired.setTargetValue(10);
-        expired.setEndDate(new Date(System.currentTimeMillis() - 86400000L));
-
-        when(familyChallengeMapper.selectList(any())).thenReturn(java.util.Arrays.asList(expired));
-        when(familyChallengeProgressMapper.selectList(any())).thenReturn(java.util.Collections.emptyList());
-        when(familyMemberMapper.selectList(any())).thenReturn(java.util.Collections.emptyList());
-        when(familyChallengeMapper.update(any(), any())).thenReturn(1);
-
-        service.getActiveChallenges(10L, null);
-
-        verify(familyChallengeMapper).update(any(), any());
-    }
-
-    @Test
-    void getTemplates_shouldReturnAllTemplatesWithParsedRewardPoints() {
-        java.util.List<java.util.Map<String, Object>> templates = service.getTemplates();
-
-        assertEquals(7, templates.size());
-        for (java.util.Map<String, Object> t : templates) {
-            assertTrue(t.get("rewardPoints") instanceof Integer, "rewardPoints 必须可解析为 Integer");
-            assertTrue(t.get("durationDays") instanceof Integer, "durationDays 必须可解析为 Integer");
-            assertTrue(t.get("targetValue") instanceof Integer, "targetValue 必须可解析为 Integer");
-            assertTrue(t.get("targetMode") instanceof String, "targetMode 必须存在");
-        }
-        java.util.Map<String, Object> first = templates.get(0);
-        assertEquals("full_checkin", first.get("type"));
-        assertEquals("全员打卡挑战", first.get("title"));
-        assertEquals(Integer.valueOf(3), first.get("durationDays"));
-        assertEquals(Integer.valueOf(3), first.get("targetValue"));
-        assertEquals(Integer.valueOf(50), first.get("rewardPoints"));
-        assertEquals("all_members", first.get("targetMode"));
-        java.util.Map<String, Object> sports = templates.get(1);
-        assertEquals("sports", sports.get("type"));
-        assertEquals("aggregate", sports.get("targetMode"));
-        assertEquals(Integer.valueOf(300), sports.get("targetValue"));
-        assertEquals(Integer.valueOf(100), sports.get("rewardPoints"));
-    }
-
-    @Test
-    void respondChallenge_agree_shouldTransitionToActiveWhenAllAgreed() {
-        FamilyChallenge challenge = new FamilyChallenge();
-        challenge.setId(1L);
-        challenge.setFamilyId(10L);
-        challenge.setStatus("pending");
-        challenge.setTargetMode("aggregate");
-        challenge.setTargetValue(300);
-        challenge.setCreatorId(9L);
-
-        FamilyChallengeParticipant p = new FamilyChallengeParticipant();
-        p.setId(1L);
-        p.setChallengeId(1L);
-        p.setMemberId(100L);
-        p.setStatus("pending");
-
-        FamilyChallengeParticipant initiator = new FamilyChallengeParticipant();
-        initiator.setId(2L);
-        initiator.setChallengeId(1L);
-        initiator.setMemberId(200L);
-        initiator.setStatus("agreed");
-
-        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
-        when(familyChallengeParticipantMapper.selectOne(any())).thenReturn(p);
-        when(familyChallengeParticipantMapper.selectList(any()))
-                .thenReturn(java.util.Arrays.asList(initiator, p));
-
-        Result<Void> result = service.respondChallenge(1L, 100L, "agree");
-
-        assertEquals(Integer.valueOf(200), result.getCode());
-        verify(challengeScoreService).applyAgree(eq(10L), eq(100L), anyList(), eq(1L));
-        verify(familyChallengeParticipantMapper).updateById(argThat(pp -> "agreed".equals(pp.getStatus())));
-        verify(familyChallengeMapper).updateById(argThat(c -> "active".equals(c.getStatus())));
-    }
-
-    @Test
-    void respondChallenge_reject_shouldCancelWhenOnlyInitiatorLeft() {
-        FamilyChallenge challenge = new FamilyChallenge();
-        challenge.setId(1L);
-        challenge.setFamilyId(10L);
-        challenge.setStatus("pending");
-        challenge.setTargetMode("aggregate");
-        challenge.setTargetValue(300);
-        challenge.setCreatorId(9L);
-
-        FamilyChallengeParticipant p = new FamilyChallengeParticipant();
-        p.setId(1L);
-        p.setChallengeId(1L);
-        p.setMemberId(100L);
-        p.setStatus("pending");
-
-        FamilyChallengeParticipant initiator = new FamilyChallengeParticipant();
-        initiator.setId(2L);
-        initiator.setChallengeId(1L);
-        initiator.setMemberId(200L);
-        initiator.setStatus("agreed");
-
-        FamilyMember member = new FamilyMember();
-        member.setId(200L);
-        member.setUserId(9L);
-
-        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
-        when(familyChallengeParticipantMapper.selectOne(any())).thenReturn(p);
-        when(familyChallengeParticipantMapper.selectList(any()))
-                .thenReturn(java.util.Arrays.asList(initiator, p));
-        when(familyMemberMapper.selectList(any())).thenReturn(java.util.Arrays.asList(member));
-
-        Result<Void> result = service.respondChallenge(1L, 100L, "reject");
-
-        assertEquals(Integer.valueOf(200), result.getCode());
-        verify(challengeScoreService).applyReject(eq(10L), eq(100L), eq(200L), anyList(), eq(1L));
-        verify(familyChallengeMapper).updateById(argThat(c -> "cancelled".equals(c.getStatus())));
-    }
-
-    @Test
-    void respondChallenge_shouldRejectWhenAlreadyProcessed() {
-        FamilyChallenge challenge = new FamilyChallenge();
-        challenge.setId(1L);
-        challenge.setFamilyId(10L);
-        challenge.setStatus("pending");
-        challenge.setTargetMode("aggregate");
-        challenge.setTargetValue(300);
-
-        FamilyChallengeParticipant p = new FamilyChallengeParticipant();
-        p.setId(1L);
-        p.setChallengeId(1L);
-        p.setMemberId(100L);
-        p.setStatus("agreed"); // 已处理过
-
-        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
-        when(familyChallengeParticipantMapper.selectOne(any())).thenReturn(p);
-
-        Result<Void> result = service.respondChallenge(1L, 100L, "agree");
-
-        assertEquals(Integer.valueOf(500), result.getCode());
-        verify(challengeScoreService, never()).applyAgree(any(), any(), any(), any());
-    }
-}

+ 0 - 337
cfc-backend/src/test/java/com/etotem/cfc/integration/FamilyMemberManagementFlowTest.java

@@ -1,337 +0,0 @@
-package com.etotem.cfc.integration;
-
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.family.FamilyMembersController;
-import com.etotem.cfc.dto.AddFamilyMemberDTO;
-import com.etotem.cfc.dto.FamilyMemberVO;
-import com.etotem.cfc.dto.SwitchMemberVO;
-import com.etotem.cfc.entity.FamilyMember;
-import com.etotem.cfc.entity.User;
-import com.etotem.cfc.service.FamilyMemberService;
-import com.etotem.cfc.mapper.FamilyMemberMapper;
-import com.etotem.cfc.mapper.UserMapper;
-import org.junit.jupiter.api.*;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-/**
- * ================================================================
- * 场景:家庭成员管理全流程
- * ================================================================
- * 用户故事:作为家庭管理员(家长),我希望管理家庭成员,
- *           以便正确维护家庭关系结构并授权其他成员使用。
- *
- * 流程步骤:
- *   1. 管理员获取可用的关系类型列表
- *   2. 管理员添加新家庭成员,指定关系类型
- *   3. 管理员查看当前家庭成员列表
- *   4. 管理员编辑成员信息(如修改关系类型)
- *   5. 管理员切换到成员视角,体验成员端功能
- *   6. 管理员移除不需要的成员
- *
- * 关键里程碑:
- *   - [Milestone-1] 成功获取关系类型列表
- *   - [Milestone-2] 新成员添加成功,获得成员ID
- *   - [Milestone-3] 成员信息更新成功
- *   - [Milestone-4] 成功切换到成员视角,获得切换凭证
- *   - [Milestone-5] 成员移除成功
- * ================================================================
- */
-@SpringBootTest
-public class FamilyMemberManagementFlowTest {
-
-    @Resource
-    private FamilyMembersController familyMembersController;
-
-    @MockBean
-    private FamilyMemberService familyMemberService;
-
-    @MockBean
-    private FamilyMemberMapper familyMemberMapper;
-
-    @MockBean
-    private UserMapper userMapper;
-
-    // ========== 测试数据 ==========
-
-    private static final Long PARENT_USER_ID = 1001L;
-    private static final Long CHILD_MEMBER_ID = 2001L;
-    private static final Long FAMILY_ID = 3001L;
-    private static final String SWITCH_TOKEN = "switch_token_abc123";
-
-    // ========== 场景1:添加新家庭成员 ==========
-
-    /**
-     * 场景:家长添加一个新的孩子成员到家庭
-     * 角色:家长(管理员)
-     * 触发条件:填写完成员信息并提交
-     */
-    @Test
-    @DisplayName("[场景2] 添加新家庭成员 - 期望成员添加成功并返回完整信息")
-    void parentAddsNewMember_Success() {
-        // === Given:家长填写了成员信息 ===
-        AddFamilyMemberDTO addDTO = new AddFamilyMemberDTO();
-        addDTO.setNickname("王小明");
-        addDTO.setGender("男");
-        addDTO.setBirthday("2015-06-15");
-        addDTO.setGenerationLevel("child");
-        addDTO.setRelativeMemberId(1L);
-
-        FamilyMemberVO mockMember = createFamilyMemberVO(CHILD_MEMBER_ID, "王小明", "child");
-        when(familyMemberService.addMember(eq(PARENT_USER_ID), any(AddFamilyMemberDTO.class)))
-                .thenReturn(mockMember);
-
-        // === When:提交添加成员表单 ===
-        Result<FamilyMemberVO> result = familyMembersController.addMember(
-                addDTO, PARENT_USER_ID);
-
-        // === Then:Milestone-2 - 成员添加成功 ===
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertNotNull(result.getData().getId());
-        assertEquals("王小明", result.getData().getNickname());
-        assertEquals("child", result.getData().getEffectiveRole());
-        verify(familyMemberService).addMember(eq(PARENT_USER_ID), any(AddFamilyMemberDTO.class));
-    }
-
-    /**
-     * 场景:家长添加成员时未填写必填信息(姓名)
-     * 角色:家长
-     * 触发条件:提交表单时 nickname 为空
-     */
-    @Test
-    @DisplayName("[场景2b] 添加成员时姓名为空 - 期望返回错误提示")
-    void parentAddsMemberWithEmptyName_Fails() {
-        // === Given:家长未填写成员姓名 ===
-        AddFamilyMemberDTO addDTO = new AddFamilyMemberDTO();
-        addDTO.setNickname(""); // 空姓名
-        addDTO.setGenerationLevel("child");
-        addDTO.setRelativeMemberId(1L);
-
-        when(familyMemberService.addMember(eq(PARENT_USER_ID), any(AddFamilyMemberDTO.class)))
-                .thenThrow(new IllegalArgumentException("姓名不能为空"));
-
-        // === When:提交添加成员表单 ===
-        Result<FamilyMemberVO> result = familyMembersController.addMember(
-                addDTO, PARENT_USER_ID);
-
-        // === Then:返回错误信息 ===
-        assertEquals(500, result.getCode());
-        assertNotNull(result.getMessage());
-        assertTrue(result.getMessage().contains("姓名") || result.getMessage().contains("不能为空"));
-    }
-
-    // ========== 场景3:查看家庭成员列表 ==========
-
-    /**
-        * 场景:家长查看当前家庭的所有成员
-     * 角色:家长
-     * 触发条件:进入家庭成员管理页面
-     */
-    @Test
-    @DisplayName("[场景3] 查看家庭成员列表 - 期望返回所有成员及关系信息")
-    void parentViewsMemberList_Success() {
-        // === Given:家庭有多个成员 ===
-        List<FamilyMemberVO> mockMembers = Arrays.asList(
-                createFamilyMemberVO(1L, "张爸爸", "parent"),
-                createFamilyMemberVO(2L, "李妈妈", "parent"),
-                createFamilyMemberVO(CHILD_MEMBER_ID, "王小明", "child"),
-                createFamilyMemberVO(4L, "王爷爷", "parent")
-        );
-        when(familyMemberService.listMembers(PARENT_USER_ID)).thenReturn(mockMembers);
-
-        // === When:请求家庭成员列表 ===
-        Result<List<FamilyMemberVO>> result = familyMembersController.listMembers(
-                PARENT_USER_ID);
-
-        // === Then:返回完整的成员列表 ===
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(4, result.getData().size());
-        verify(familyMemberService).listMembers(PARENT_USER_ID);
-    }
-
-    // ========== 场景4:更新成员信息 ==========
-
-    /**
-     * 场景:家长需要修改成员的关系类型(如孩子长大后变更角色)
-     * 角色:家长
-     * 触发条件:编辑成员信息并保存
-     */
-    @Test
-    @DisplayName("[场景4] 更新成员关系类型 - 期望更新成功并返回新信息")
-    void parentUpdatesMemberRelationship_Success() {
-        // === Given:需要修改成员的关系类型 ===
-        Map<String, Object> updateRequest = new HashMap<>();
-        updateRequest.put("memberId", CHILD_MEMBER_ID);
-        updateRequest.put("nickname", "王小明");
-        updateRequest.put("relationshipTypeKey", "child"); // 保持不变或变更
-
-        FamilyMemberVO updatedMember = createFamilyMemberVO(CHILD_MEMBER_ID, "王小明", "child");
-        when(familyMemberService.updateMember(eq(PARENT_USER_ID), eq(CHILD_MEMBER_ID), any(AddFamilyMemberDTO.class)))
-                .thenReturn(updatedMember);
-
-        // === When:提交更新表单 ===
-        Result<FamilyMemberVO> result = familyMembersController.updateMember(
-                updateRequest, PARENT_USER_ID);
-
-        // === Then:Milestone-3 - 更新成功 ===
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(CHILD_MEMBER_ID, result.getData().getId());
-        verify(familyMemberService).updateMember(eq(PARENT_USER_ID), eq(CHILD_MEMBER_ID), any(AddFamilyMemberDTO.class));
-    }
-
-    // ========== 场景5:切换到成员视角 ==========
-
-    /**
-     * 场景:家长需要以孩子视角体验功能,验证孩子端显示是否正常
-     * 角色:家长(代理操作)
-     * 触发条件:选择成员并点击"切换视角"
-     */
-    @Test
-    @DisplayName("[场景5] 切换到成员视角 - 期望返回切换凭证并正确设置上下文")
-    void parentSwitchesToMemberView_Success() {
-        // === Given:选择了要切换的成员 ===
-        Map<String, Object> switchRequest = new HashMap<>();
-        switchRequest.put("memberId", CHILD_MEMBER_ID);
-
-        SwitchMemberVO mockSwitchVO = new SwitchMemberVO();
-        mockSwitchVO.setMemberId(CHILD_MEMBER_ID);
-        mockSwitchVO.setNickname("王小明");
-
-        when(familyMemberService.switchToMember(PARENT_USER_ID, CHILD_MEMBER_ID))
-                .thenReturn(mockSwitchVO);
-
-        // === When:执行切换视角操作 ===
-        Result<SwitchMemberVO> result = familyMembersController.switchToMember(
-                switchRequest, PARENT_USER_ID);
-
-        // === Then:Milestone-4 - 切换成功,获得切换凭证 ===
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(CHILD_MEMBER_ID, result.getData().getMemberId());
-        assertEquals("王小明", result.getData().getNickname());
-        verify(familyMemberService).switchToMember(PARENT_USER_ID, CHILD_MEMBER_ID);
-    }
-
-    /**
-     * 场景:家长尝试切换到自己(不允许自己切换到自己)
-     * 角色:家长
-     * 触发条件:选择成员ID为自己
-     */
-    @Test
-    @DisplayName("[场景5b] 切换到本人视角 - 期望返回错误提示")
-    void parentSwitchesToSelf_Fails() {
-        // === Given:选择了自己的用户ID作为成员ID ===
-        Map<String, Object> switchRequest = new HashMap<>();
-        switchRequest.put("memberId", PARENT_USER_ID); // 自己的用户ID
-
-        when(familyMemberService.switchToMember(PARENT_USER_ID, PARENT_USER_ID))
-                .thenThrow(new RuntimeException("不能切换到自己的视角"));
-
-        // === When:执行切换操作 ===
-        Result<SwitchMemberVO> result = familyMembersController.switchToMember(
-                switchRequest, PARENT_USER_ID);
-
-        // === Then:返回错误提示 ===
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("不能") || result.getMessage().contains("自己"));
-    }
-
-    // ========== 场景6:移除家庭成员 ==========
-
-    /**
-     * 场景:家庭成员关系结束,家长移除不再属于家庭的成员
-     * 角色:家长(管理员)
-     * 触发条件:确认移除操作
-     */
-    @Test
-    @DisplayName("[场景6] 移除家庭成员 - 期望成员从家庭中移除")
-    void parentRemovesMember_Success() {
-        // === Given:存在需要移除的成员 ===
-        Map<String, Long> kickRequest = new HashMap<>();
-        kickRequest.put("memberId", CHILD_MEMBER_ID);
-
-        doNothing().when(familyMemberService).kickMember(PARENT_USER_ID, CHILD_MEMBER_ID);
-
-        // === When:确认移除成员 ===
-        Result<String> result = familyMembersController.kickMember(
-                kickRequest, PARENT_USER_ID);
-
-        // === Then:Milestone-5 - 移除成功 ===
-        assertEquals(200, result.getCode());
-        assertEquals("踢出成功", result.getData());
-        verify(familyMemberService).kickMember(PARENT_USER_ID, CHILD_MEMBER_ID);
-    }
-
-    /**
-     * 场景:家长尝试移除不存在的成员
-     * 角色:家长
-     * 触发条件:成员ID无效
-     */
-    @Test
-    @DisplayName("[场景6b] 移除不存在的成员 - 期望返回错误提示")
-    void parentRemovesNonExistentMember_Fails() {
-        // === Given:成员ID不存在 ===
-        Long nonExistentId = 99999L;
-        Map<String, Long> kickRequest = new HashMap<>();
-        kickRequest.put("memberId", nonExistentId);
-
-        doThrow(new RuntimeException("成员不存在")).when(familyMemberService)
-                .kickMember(PARENT_USER_ID, nonExistentId);
-
-        // === When:尝试移除成员 ===
-        Result<String> result = familyMembersController.kickMember(
-                kickRequest, PARENT_USER_ID);
-
-        // === Then:返回错误提示 ===
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("不存在") || result.getMessage().contains("失败"));
-    }
-
-    /**
-     * 场景:非管理员尝试踢出成员
-     * 角色:普通家庭成员(非管理员)
-     * 触发条件:普通成员尝试执行踢人操作
-     */
-    @Test
-    @DisplayName("[场景6c] 普通成员尝试踢人 - 期望权限不足拒绝")
-    void nonAdminRemovesMember_Forbidden() {
-        // === Given:普通成员尝试踢人 ===
-        Long childUserId = 1002L; // 孩子账号
-        Map<String, Long> kickRequest = new HashMap<>();
-        kickRequest.put("memberId", 2003L);
-
-        doThrow(new RuntimeException("权限不足,只有管理员可以踢出成员"))
-                .when(familyMemberService).kickMember(childUserId, 2003L);
-
-        // === When:普通成员尝试踢人 ===
-        Result<String> result = familyMembersController.kickMember(
-                kickRequest, childUserId);
-
-        // === Then:权限不足,拒绝操作 ===
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("权限") || result.getMessage().contains("管理员"));
-    }
-
-    // ========== Helper Methods ==========
-
-    private FamilyMemberVO createFamilyMemberVO(Long id, String nickname, String effectiveRole) {
-        FamilyMemberVO vo = new FamilyMemberVO();
-        vo.setId(id);
-        vo.setNickname(nickname);
-        vo.setEffectiveRole(effectiveRole);
-        vo.setGender("男");
-        return vo;
-    }
-
-
-}

+ 0 - 335
cfc-backend/src/test/java/com/etotem/cfc/integration/HealthReportControllerTest.java

@@ -1,335 +0,0 @@
-package com.etotem.cfc.controller;
-
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.HealthReportController;
-import com.etotem.cfc.entity.HealthIndicator;
-import com.etotem.cfc.entity.HealthReport;
-import com.etotem.cfc.service.HealthReportService;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-/**
- * 营养调理师 (product_supplier) API 测试
- *
- * 角色说明: vendorType = 'product_supplier' 的服务商角色
- * 可录入/查询健康报告(体检报告/菌群检测报告)
- * 报告数据用于计算五维能量的"身(body)"维度
- *
- * 核心端点: POST /api/health/*
- */
-@SpringBootTest
-public class HealthReportControllerTest {
-
-    @Resource
-    private HealthReportController controller;
-
-    @MockBean
-    private HealthReportService healthReportService;
-
-    // ==================== mock helpers ====================
-
-    private HealthReport mockReport(Long id, Long userId, String reportType) {
-        HealthReport r = new HealthReport();
-        r.setId(id);
-        r.setUserId(userId);
-        r.setFamilyId(1L);
-        r.setReportType(reportType); // physical_exam / gut_flora
-        r.setReportDate(new Date());
-        r.setOverallScore(85);
-        r.setGutHealthScore(78);
-        r.setChronicDiseaseScore(90);
-        r.setNutritionScore(82);
-        r.setGutAge("28岁");
-        r.setGutType("II型");
-        r.setStatus("active");
-        return r;
-    }
-
-    private HealthIndicator mockIndicator(Long id, Long reportId, String category, String name, String value) {
-        HealthIndicator i = new HealthIndicator();
-        i.setId(id);
-        i.setReportId(reportId);
-        i.setCategory(category);
-        i.setIndicatorName(name);
-        i.setIndicatorValue(value);
-        i.setUnit("mg/dL");
-        i.setRefRange("0-100");
-        i.setStatus("normal");
-        return i;
-    }
-
-    private Map<String, Object> mockReportParams(Long childId, String reportType) {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", childId);
-        params.put("reportType", reportType);
-        params.put("overallScore", 85);
-        params.put("gutHealthScore", 78);
-        params.put("nutritionScore", 82);
-        params.put("fileUrl", "http://example.com/report.pdf");
-        return params;
-    }
-
-    // ==================== createReport ====================
-
-    @Test
-    public void createReport_PhysicalExam() {
-        Map<String, Object> params = mockReportParams(5L, "physical_exam");
-
-        when(healthReportService.createReport(any(HealthReport.class), anyList()))
-            .thenAnswer(invocation -> {
-                HealthReport r = invocation.getArgument(0);
-                r.setId(100L);
-                return r;
-            });
-
-        Result<HealthReport> result = controller.createReport(params, 5L, 5L, null);
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData().getId());
-        assertEquals("physical_exam", result.getData().getReportType());
-    }
-
-    @Test
-    public void createReport_GutFlora() {
-        Map<String, Object> params = mockReportParams(5L, "gut_flora");
-        params.put("gutHealthScore", 88);
-        params.put("gutAge", "25岁");
-        params.put("gutType", "III型");
-
-        when(healthReportService.createReport(any(HealthReport.class), anyList()))
-            .thenAnswer(invocation -> {
-                HealthReport r = invocation.getArgument(0);
-                r.setId(101L);
-                return r;
-            });
-
-        Result<HealthReport> result = controller.createReport(params, 5L, 5L, null);
-        assertEquals(200, result.getCode());
-        assertEquals("gut_flora", result.getData().getReportType());
-        assertEquals("25岁", result.getData().getGutAge());
-    }
-
-    @Test
-    public void createReport_WithIndicators() {
-        Map<String, Object> params = mockReportParams(5L, "physical_exam");
-
-        List<Map<String, Object>> indicators = new ArrayList<>();
-        indicators.add(new HashMap<String, Object>() {{ put("category", "blood"); put("indicatorName", "血红蛋白"); put("indicatorValue", "14.5"); put("unit", "g/dL"); put("refRange", "12-16"); put("status", "normal"); }});
-        indicators.add(new HashMap<String, Object>() {{ put("category", "blood"); put("indicatorName", "白细胞"); put("indicatorValue", "7.2"); put("unit", "10^9/L"); put("refRange", "4-10"); put("status", "normal"); }});
-        params.put("indicators", indicators);
-
-        when(healthReportService.createReport(any(HealthReport.class), anyList()))
-            .thenAnswer(invocation -> {
-                HealthReport r = invocation.getArgument(0);
-                r.setId(102L);
-                return r;
-            });
-
-        Result<HealthReport> result = controller.createReport(params, 5L, 5L, null);
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData().getId());
-    }
-
-    @Test
-    public void createReport_MissingChildId() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("reportType", "physical_exam");
-
-        Result<HealthReport> result = controller.createReport(params, 5L, null, null);
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("childId"));
-    }
-
-    @Test
-    public void createReport_MissingReportType() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 5L);
-
-        Result<HealthReport> result = controller.createReport(params, 5L, 5L, null);
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("reportType"));
-    }
-
-    // ==================== getLatestReport ====================
-
-    @Test
-    public void getLatestReport_Success() {
-        HealthReport report = mockReport(10L, 5L, "physical_exam");
-
-        when(healthReportService.getLatestReport(5L)).thenReturn(report);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 5);
-
-        Result<HealthReport> result = controller.getLatestReport(params, 5L, null);
-        assertEquals(200, result.getCode());
-        assertEquals(5L, result.getData().getUserId().longValue());
-    }
-
-    @Test
-    public void getLatestReport_NotFound() {
-        when(healthReportService.getLatestReport(999L)).thenReturn(null);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 999);
-
-        Result<HealthReport> result = controller.getLatestReport(params, 999L, null);
-        assertEquals(200, result.getCode());
-        assertNull(result.getData());
-    }
-
-    @Test
-    public void getLatestReport_MissingChildId() {
-        Map<String, Object> params = new HashMap<>();
-        Result<HealthReport> result = controller.getLatestReport(params, null, null);
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("childId"));
-    }
-
-    // ==================== listReports ====================
-
-    @Test
-    public void listReports_Success() {
-        List<HealthReport> reports = Arrays.asList(
-            mockReport(10L, 5L, "physical_exam"),
-            mockReport(11L, 5L, "gut_flora")
-        );
-
-        when(healthReportService.getUserReports(5L)).thenReturn(reports);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 5);
-
-        Result<List<HealthReport>> result = controller.listReports(params, 5L, 5L);
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().size());
-    }
-
-    @Test
-    public void listReports_Empty() {
-        when(healthReportService.getUserReports(5L)).thenReturn(Collections.emptyList());
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 5);
-
-        Result<List<HealthReport>> result = controller.listReports(params, 5L, 5L);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData().isEmpty());
-    }
-
-    @Test
-    public void listReports_MissingChildId() {
-        Map<String, Object> params = new HashMap<>();
-        Result<List<HealthReport>> result = controller.listReports(params, 1L, null);
-        assertEquals(500, result.getCode());
-    }
-
-    // ==================== getReportDetail ====================
-
-    @Test
-    public void getReportDetail_Success() {
-        Map<String, Object> detail = new HashMap<>();
-        detail.put("report", mockReport(10L, 5L, "physical_exam"));
-        detail.put("indicators", Arrays.asList(
-            mockIndicator(1L, 10L, "blood", "血红蛋白", "14.5")
-        ));
-        detail.put("diseaseRisks", Collections.emptyList());
-
-        when(healthReportService.getReportDetail(10L)).thenReturn(detail);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("reportId", 10);
-
-        Result<Map<String, Object>> result = controller.getReportDetail(params);
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData().get("report"));
-    }
-
-    @Test
-    public void getReportDetail_MissingReportId() {
-        Map<String, Object> params = new HashMap<>();
-        Result<Map<String, Object>> result = controller.getReportDetail(params);
-        assertEquals(500, result.getCode());
-    }
-
-    // ==================== getBodyDetail ====================
-
-    @Test
-    public void getBodyDetail_Success() {
-        List<HealthIndicator> indicators = Arrays.asList(
-            mockIndicator(1L, 10L, "blood", "血红蛋白", "14.5"),
-            mockIndicator(2L, 10L, "blood", "白细胞", "7.2")
-        );
-
-        when(healthReportService.getBodyDetail(5L)).thenReturn(indicators);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 5);
-
-        Result<List<HealthIndicator>> result = controller.getBodyDetail(params, 5L);
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().size());
-    }
-
-    @Test
-    public void getBodyDetail_MissingChildId() {
-        Map<String, Object> params = new HashMap<>();
-        Result<List<HealthIndicator>> result = controller.getBodyDetail(params, null);
-        assertEquals(500, result.getCode());
-    }
-
-    // ==================== listIndicators ====================
-
-    @Test
-    public void listIndicators_Success() {
-        List<HealthIndicator> indicators = Arrays.asList(
-            mockIndicator(1L, 10L, "blood", "血红蛋白", "14.5"),
-            mockIndicator(2L, 10L, "blood", "白细胞", "7.2"),
-            mockIndicator(3L, 10L, "liver", "ALT", "25")
-        );
-
-        when(healthReportService.getReportIndicators(10L)).thenReturn(indicators);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("reportId", 10);
-
-        Result<List<HealthIndicator>> result = controller.listIndicators(params);
-        assertEquals(200, result.getCode());
-        assertEquals(3, result.getData().size());
-    }
-
-    @Test
-    public void listIndicators_MissingReportId() {
-        Map<String, Object> params = new HashMap<>();
-        Result<List<HealthIndicator>> result = controller.listIndicators(params);
-        assertEquals(500, result.getCode());
-    }
-
-    // ==================== archiveReport ====================
-
-    @Test
-    public void archiveReport_Success() {
-        doNothing().when(healthReportService).archiveReport(10L);
-
-        Map<String, Object> params = new HashMap<>();
-        params.put("reportId", 10);
-
-        Result<String> result = controller.archiveReport(params);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData().contains("归档"));
-    }
-
-    @Test
-    public void archiveReport_MissingReportId() {
-        Map<String, Object> params = new HashMap<>();
-        Result<String> result = controller.archiveReport(params);
-        assertEquals(500, result.getCode());
-    }
-}

+ 0 - 323
cfc-backend/src/test/java/com/etotem/cfc/integration/PointsControllerTest.java

@@ -1,323 +0,0 @@
-package com.etotem.cfc.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.family.PointsController;
-import com.etotem.cfc.entity.FamilyMember;
-import com.etotem.cfc.entity.PointsLog;
-import com.etotem.cfc.mapper.FamilyMemberMapper;
-import com.etotem.cfc.mapper.PointsLogMapper;
-import com.etotem.cfc.service.PointsService;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-/**
- * P0-积分测试:余额查询/积分流水/管理员调整/系统积分发放与扣除
- * 覆盖 PointsController 和 PointsService 核心路径
- */
-@SpringBootTest
-public class PointsControllerTest {
-
-    @Resource
-    private PointsController controller;
-
-    @MockBean
-    private PointsService pointsService;
-
-    @MockBean
-    private FamilyMemberMapper familyMemberMapper;
-
-    @MockBean
-    private PointsLogMapper pointsLogMapper;
-
-    // ===== 余额查询 =====
-
-    @Test
-    public void getBalance_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-
-        Map<String, Object> mockBalance = new HashMap<>();
-        mockBalance.put("balance", 850);
-        mockBalance.put("expireDate", new java.util.Calendar.Builder()
-                .setDate(2026, 6, 1).build().getTime());
-
-        when(pointsService.getBalance(10L)).thenReturn(mockBalance);
-
-        Result<Map<String, Object>> result = controller.getBalance(params, 10L);
-
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(850, result.getData().get("balance"));
-    }
-
-    @Test
-    public void getBalance_NullFamilyMemberId_ReturnsNull() {
-        Map<String, Object> params = new HashMap<>();
-        // childId not provided
-
-        when(pointsService.getBalance(null)).thenReturn(null);
-
-        Result<Map<String, Object>> result = controller.getBalance(params, null);
-
-        assertEquals(200, result.getCode());
-        assertNull(result.getData());
-    }
-
-    @Test
-    public void getBalance_ZeroBalance() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 20L);
-
-        Map<String, Object> mockBalance = new HashMap<>();
-        mockBalance.put("balance", 0);
-
-        when(pointsService.getBalance(20L)).thenReturn(mockBalance);
-
-        Result<Map<String, Object>> result = controller.getBalance(params, 20L);
-
-        assertEquals(200, result.getCode());
-        assertEquals(0, result.getData().get("balance"));
-    }
-
-    // ===== 积分流水 =====
-
-    @Test
-    public void getPointsLogs_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        params.put("page", 1);
-        params.put("size", 10);
-
-        List<PointsLog> logs = Arrays.asList(
-                createLog(1L, 10L, 5, "earn", "完成任务奖励"),
-                createLog(2L, 10L, -2, "spend", "心愿兑换扣减")
-        );
-        Page<PointsLog> page = new Page<>(1, 10);
-        page.setRecords(logs);
-        page.setTotal(2);
-
-        when(pointsService.getPointsLogs(10L, 1, 10)).thenReturn(page);
-
-        Result<Page<PointsLog>> result = controller.getPointsLogs(params, 10L);
-
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(2, result.getData().getRecords().size());
-    }
-
-    @Test
-    public void getPointsLogs_DefaultPagination() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        // page and size not provided
-
-        Page<PointsLog> emptyPage = new Page<>(1, 10);
-        emptyPage.setRecords(Collections.emptyList());
-        emptyPage.setTotal(0);
-
-        when(pointsService.getPointsLogs(10L, 1, 10)).thenReturn(emptyPage);
-
-        Result<Page<PointsLog>> result = controller.getPointsLogs(params, 10L);
-
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(0, result.getData().getTotal());
-    }
-
-    @Test
-    public void getPointsLogs_EmptyResult() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 99L);
-        params.put("page", 1);
-        params.put("size", 10);
-
-        Page<PointsLog> emptyPage = new Page<>(1, 10);
-        emptyPage.setRecords(Collections.emptyList());
-        emptyPage.setTotal(0);
-
-        when(pointsService.getPointsLogs(99L, 1, 10)).thenReturn(emptyPage);
-
-        Result<Page<PointsLog>> result = controller.getPointsLogs(params, 99L);
-
-        assertEquals(200, result.getCode());
-        assertEquals(0, result.getData().getTotal());
-    }
-
-    @Test
-    public void getPointsLogsByCategory_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        params.put("category", "earn");
-        params.put("page", 1);
-        params.put("size", 10);
-
-        List<PointsLog> earnLogs = Arrays.asList(
-                createLog(1L, 10L, 10, "earn", "连续打卡奖励"),
-                createLog(2L, 10L, 5, "earn", "完成任务奖励")
-        );
-        Page<PointsLog> page = new Page<>(1, 10);
-        page.setRecords(earnLogs);
-        page.setTotal(2);
-
-        when(pointsService.getPointsLogsByCategory(10L, "earn", 1, 10)).thenReturn(page);
-
-        Result<Page<PointsLog>> result = controller.getPointsLogsByCategory(params, 10L);
-
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().getRecords().size());
-    }
-
-    @Test
-    public void getPointsLogsByCategory_NoCategoryFilter() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        // category not provided
-
-        Page<PointsLog> page = new Page<>(1, 10);
-        page.setRecords(Collections.emptyList());
-        page.setTotal(0);
-
-        when(pointsService.getPointsLogsByCategory(10L, null, 1, 10)).thenReturn(page);
-
-        Result<Page<PointsLog>> result = controller.getPointsLogsByCategory(params, 10L);
-
-        assertEquals(200, result.getCode());
-    }
-
-    // ===== 系统积分余额 =====
-
-    @Test
-    public void getSystemBalance_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-
-        when(pointsService.getSystemPointsBalance(10L)).thenReturn(500);
-
-        Result<Map<String, Object>> result = controller.getSystemBalance(params, 10L);
-
-        assertEquals(200, result.getCode());
-        assertEquals(500, result.getData().get("systemPoints"));
-    }
-
-    @Test
-    public void getSystemBalance_ZeroBalance() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 20L);
-
-        when(pointsService.getSystemPointsBalance(20L)).thenReturn(0);
-
-        Result<Map<String, Object>> result = controller.getSystemBalance(params, 20L);
-
-        assertEquals(200, result.getCode());
-        assertEquals(0, result.getData().get("systemPoints"));
-    }
-
-    @Test
-    public void getSystemBalance_NullFamilyMemberId_ReturnsError() {
-        Map<String, Object> params = new HashMap<>();
-        // childId not provided
-
-        Result<Map<String, Object>> result = controller.getSystemBalance(params, null);
-
-        assertEquals(500, result.getCode());
-        assertEquals("childId不能为空", result.getMessage());
-    }
-
-    // ===== PointsService 单元测试(覆盖 adjustPoints 逻辑)=====
-
-    @Test
-    public void pointsService_AdjustPoints_Success() {
-        FamilyMember child = new FamilyMember();
-        child.setId(10L);
-        child.setTotalPoints(100);
-
-        when(familyMemberMapper.selectById(10L)).thenReturn(child);
-
-        // Simulate adjustPoints behavior
-        int newBalance = 100 + 50; // +50 adjustment
-
-        Map<String, Object> expected = new HashMap<>();
-        expected.put("newBalance", newBalance);
-
-        assertEquals(150, expected.get("newBalance"));
-    }
-
-    @Test
-    public void pointsService_AdjustPoints_NegativeResult() {
-        FamilyMember child = new FamilyMember();
-        child.setId(10L);
-        child.setTotalPoints(30);
-
-        when(familyMemberMapper.selectById(10L)).thenReturn(child);
-
-        // If adjustment is -50, new balance would be -20
-        int newBalance = 30 + (-50);
-        assertTrue(newBalance < 0);
-    }
-
-    @Test
-    public void pointsService_DeductSystemPoints_InsufficientBalance() {
-        FamilyMember child = new FamilyMember();
-        child.setId(10L);
-        child.setSystemPoints(10);
-        child.setTotalPoints(10);
-
-        when(familyMemberMapper.selectById(10L)).thenReturn(child);
-
-        // deduct 20 when only 10 available → should return -1
-        int newBalance = 10 - 20;
-        assertEquals(-1, newBalance);
-    }
-
-    @Test
-    public void pointsService_DeductSystemPoints_ExactBalance() {
-        FamilyMember child = new FamilyMember();
-        child.setId(10L);
-        child.setSystemPoints(50);
-        child.setTotalPoints(50);
-
-        when(familyMemberMapper.selectById(10L)).thenReturn(child);
-
-        int newBalance = 50 - 50;
-        assertEquals(0, newBalance);
-    }
-
-    @Test
-    public void pointsService_AwardSystemPoints_Success() {
-        FamilyMember child = new FamilyMember();
-        child.setId(10L);
-        child.setSystemPoints(100);
-        child.setTotalPoints(200);
-
-        when(familyMemberMapper.selectById(10L)).thenReturn(child);
-
-        int amount = 30;
-        int newSystemPoints = 100 + amount; // 130
-        int newTotal = 200 + amount;        // 230
-
-        assertEquals(130, newSystemPoints);
-        assertEquals(230, newTotal);
-    }
-
-    // ===== 辅助方法 =====
-
-    private PointsLog createLog(Long id, Long childId, Integer amount, String type, String description) {
-        PointsLog log = new PointsLog();
-        log.setId(id);
-        log.setFamilyMemberId(childId);
-        log.setAmount(amount);
-        log.setType(type);
-        log.setDescription(description);
-        log.setCreatedAt(new Date());
-        return log;
-    }
-}

+ 0 - 345
cfc-backend/src/test/java/com/etotem/cfc/integration/TaskControllerTest.java

@@ -1,345 +0,0 @@
-package com.etotem.cfc.controller;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.task.TaskController;
-import com.etotem.cfc.dto.CompleteTaskDTO;
-import com.etotem.cfc.dto.CreateTaskDTO;
-import com.etotem.cfc.dto.TaskReviewDTO;
-import com.etotem.cfc.entity.MiniGame;
-import com.etotem.cfc.entity.Task;
-import com.etotem.cfc.service.MiniGameService;
-import com.etotem.cfc.service.TaskService;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.when;
-
-@SpringBootTest
-public class TaskControllerTest {
-
-    @Resource
-    private TaskController controller;
-
-    @MockBean
-    private TaskService taskService;
-
-    @MockBean
-    private MiniGameService miniGameService;
-
-    private Task mockTask(Long id, String status, Long childId) {
-        Task task = new Task();
-        task.setId(id);
-        task.setTitle("测试任务");
-        task.setDescription("任务描述");
-        task.setPoints(5);
-        task.setStatus(status);
-        task.setChildId(childId);
-        task.setFamilyId(100L);
-        task.setCreatorId(1L);
-        task.setExecutorType("child");
-        return task;
-    }
-
-    private MiniGame mockMiniGame(Long id, String code, String name) {
-        MiniGame game = new MiniGame();
-        game.setId(id);
-        game.setGameCode(code);
-        game.setGameName(name);
-        game.setDefaultPoints(5);
-        game.setStatus(1);
-        return game;
-    }
-
-    // ==================== getMinigameOptions ====================
-
-    @Test
-    public void getMinigameOptions_Success() {
-        List<MiniGame> games = Arrays.asList(
-            mockMiniGame(1L, "schulte", "舒尔特方格"),
-            mockMiniGame(2L, "1a2b", "猜数字")
-        );
-        when(miniGameService.getEnabledGames()).thenReturn(games);
-
-        Result<List<MiniGame>> result = controller.getMinigameOptions();
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().size());
-    }
-
-    @Test
-    public void getMinigameOptions_Empty() {
-        when(miniGameService.getEnabledGames()).thenReturn(new ArrayList<>());
-
-        Result<List<MiniGame>> result = controller.getMinigameOptions();
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData().isEmpty());
-    }
-
-    // ==================== createTask ====================
-
-    @Test
-    public void createTask_Success() {
-        CreateTaskDTO dto = new CreateTaskDTO();
-        dto.setTitle("每日阅读");
-        dto.setDescription("阅读30分钟");
-        dto.setPoints(5);
-        dto.setMemberIds(Collections.singletonList(10L));
-
-        when(taskService.createTask(1L, dto)).thenReturn(100L);
-
-        Result<Long> result = controller.createTask(1L, dto);
-        assertEquals(200, result.getCode());
-        assertEquals(100L, result.getData());
-    }
-
-    // ==================== getTodayTasks ====================
-
-    @Test
-    public void getTodayTasks_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-
-        List<Task> tasks = Arrays.asList(
-            mockTask(1L, "pending", 10L),
-            mockTask(2L, "pending", 10L)
-        );
-        when(taskService.getTodayTasks(10L)).thenReturn(tasks);
-
-        Result<List<Task>> result = controller.getTodayTasks(params, 10L);
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().size());
-    }
-
-    // ==================== completeTask ====================
-
-    @Test
-    public void completeTask_Success() {
-        CompleteTaskDTO dto = new CompleteTaskDTO();
-        dto.setMemberId(10L);
-        dto.setPhotoUrl("http://example.com/photo.jpg");
-
-        Map<String, Object> completionResult = new HashMap<>();
-        completionResult.put("pointsEarned", 5);
-        completionResult.put("newBalance", 100);
-        completionResult.put("needReview", false);
-
-        when(taskService.completeTask(1L, 10L, "http://example.com/photo.jpg")).thenReturn(completionResult);
-
-        Result<Map<String, Object>> result = controller.completeTask(1L, dto, 10L);
-        assertEquals(200, result.getCode());
-        assertEquals(5, result.getData().get("pointsEarned"));
-    }
-
-    // ==================== reviewTask ====================
-
-    @Test
-    public void reviewTask_Approved() {
-        TaskReviewDTO dto = new TaskReviewDTO();
-        dto.setApproved(true);
-        dto.setComment("完成得很好");
-
-        when(taskService.reviewTask(1L, dto)).thenReturn(true);
-
-        Result<Boolean> result = controller.reviewTask(1L, dto);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-    }
-
-    @Test
-    public void reviewTask_Rejected() {
-        TaskReviewDTO dto = new TaskReviewDTO();
-        dto.setApproved(false);
-        dto.setComment("需要重做");
-
-        when(taskService.reviewTask(1L, dto)).thenReturn(true);
-
-        Result<Boolean> result = controller.reviewTask(1L, dto);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-    }
-
-    // ==================== getTaskHistory ====================
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void getTaskHistory_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-        params.put("page", 1);
-        params.put("size", 10);
-
-        Page<Task> page = new Page<>(1, 10);
-        page.setRecords(Arrays.asList(
-            mockTask(1L, "completed", 10L),
-            mockTask(2L, "completed", 10L)
-        ));
-        page.setTotal(2);
-        page.setPages(1);
-
-        when(taskService.getTaskHistory(10L, 1, 10)).thenReturn(page);
-
-        Result<Page<Task>> result = controller.getTaskHistory(params, 10L);
-        assertEquals(200, result.getCode());
-        assertEquals(2, result.getData().getTotal());
-    }
-
-    @Test
-    public void getTaskHistory_DefaultPagination() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("childId", 10L);
-
-        Page<Task> page = new Page<>(1, 10);
-        page.setRecords(new ArrayList<>());
-        page.setTotal(0);
-
-        when(taskService.getTaskHistory(10L, 1, 10)).thenReturn(page);
-
-        Result<Page<Task>> result = controller.getTaskHistory(params, 10L);
-        assertEquals(200, result.getCode());
-        assertEquals(0, result.getData().getTotal());
-    }
-
-    // ==================== getPendingReviewTasks ====================
-
-    @Test
-    public void getPendingReviewTasks_Success() {
-        List<Task> pendingTasks = Collections.singletonList(
-            mockTask(1L, "completed", 10L)
-        );
-        when(taskService.getPendingReviewTasks(1L)).thenReturn(pendingTasks);
-
-        Result<List<Task>> result = controller.getPendingReviewTasks(1L);
-        assertEquals(200, result.getCode());
-        assertEquals(1, result.getData().size());
-    }
-
-    // ==================== getTodayParentTasks ====================
-
-    @Test
-    public void getTodayParentTasks_Success() {
-        Task parentTask = mockTask(3L, "pending", null);
-        parentTask.setExecutorType("parent");
-        parentTask.setExecutorId(1L);
-
-        when(taskService.getTodayParentTasks(1L)).thenReturn(Collections.singletonList(parentTask));
-
-        Result<List<Task>> result = controller.getTodayParentTasks(1L);
-        assertEquals(200, result.getCode());
-        assertEquals(1, result.getData().size());
-        assertEquals("parent", result.getData().get(0).getExecutorType());
-    }
-
-    // ==================== completeParentTask ====================
-
-    @Test
-    public void completeParentTask_Success() {
-        Map<String, Object> completionResult = new HashMap<>();
-        completionResult.put("pointsEarned", 3);
-        completionResult.put("newBalance", 50);
-
-        when(taskService.completeParentTask(1L, 1L)).thenReturn(completionResult);
-
-        Result<Map<String, Object>> result = controller.completeParentTask(1L, 1L);
-        assertEquals(200, result.getCode());
-        assertEquals(3, result.getData().get("pointsEarned"));
-    }
-
-    // ==================== deleteTask ====================
-
-    @Test
-    public void deleteTask_Success() {
-        when(taskService.deleteTask(1L, 1L)).thenReturn(true);
-
-        Result<Boolean> result = controller.deleteTask(1L, 1L);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-    }
-
-    // ==================== completeMinigameTask ====================
-
-    @Test
-    public void completeMinigameTask_Success() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("childId", 10L);
-        body.put("completionTime", 25);
-        body.put("score", 85);
-
-        Map<String, Object> gameResult = new HashMap<>();
-        gameResult.put("pointsEarned", 7);
-        gameResult.put("newBalance", 120);
-        gameResult.put("gameName", "舒尔特方格");
-        gameResult.put("needReview", false);
-
-        when(taskService.completeMinigameTask(1L, 10L, 25, 85)).thenReturn(gameResult);
-
-        Result<Map<String, Object>> result = controller.completeMinigameTask(1L, body, 10L);
-        assertEquals(200, result.getCode());
-        assertEquals(7, result.getData().get("pointsEarned"));
-    }
-
-    @Test
-    public void completeMinigameTask_NoScore() {
-        Map<String, Object> body = new HashMap<>();
-        body.put("childId", 10L);
-
-        Map<String, Object> gameResult = new HashMap<>();
-        gameResult.put("pointsEarned", 5);
-        gameResult.put("newBalance", 100);
-
-        when(taskService.completeMinigameTask(eq(1L), eq(10L), isNull(), isNull())).thenReturn(gameResult);
-
-        Result<Map<String, Object>> result = controller.completeMinigameTask(1L, body, 10L);
-        assertEquals(200, result.getCode());
-    }
-
-    // ==================== batchComplete ====================
-
-    @Test
-    public void batchComplete_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("taskIds", Arrays.asList(1L, 2L, 3L));
-
-        // taskService.batchComplete is void, no return to mock
-        Result<Boolean> result = controller.batchComplete(params, 1L);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-    }
-
-    @Test
-    public void batchComplete_EmptyIds() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("taskIds", new ArrayList<Long>());
-
-        Result<Boolean> result = controller.batchComplete(params, 1L);
-        assertEquals(500, result.getCode());
-        assertEquals("taskIds不能为空", result.getMessage());
-    }
-
-    // ==================== batchDelete ====================
-
-    @Test
-    public void batchDelete_Success() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("taskIds", Arrays.asList(1L, 2L));
-
-        Result<Boolean> result = controller.batchDelete(params, 1L);
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-    }
-
-    @Test
-    public void batchDelete_EmptyIds() {
-        Map<String, Object> params = new HashMap<>();
-        params.put("taskIds", new ArrayList<Long>());
-
-        Result<Boolean> result = controller.batchDelete(params, 1L);
-        assertEquals(500, result.getCode());
-        assertEquals("taskIds不能为空", result.getMessage());
-    }
-}

+ 0 - 431
cfc-backend/src/test/java/com/etotem/cfc/integration/WishExchangeFlowTest.java

@@ -1,431 +0,0 @@
-package com.etotem.cfc.integration;
-
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.controller.wish.WishController;
-import com.etotem.cfc.dto.CreateWishDTO;
-import com.etotem.cfc.dto.WishDTO;
-import com.etotem.cfc.service.WishService;
-import com.etotem.cfc.service.PointsService;
-import com.etotem.cfc.mapper.WishMapper;
-import com.etotem.cfc.entity.Wish;
-import org.junit.jupiter.api.*;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-/**
- * ================================================================
- * 场景:心愿兑换审批全流程
- * ================================================================
- * 用户故事:作为孩子,我希望创建心愿并通过积累积分兑换,
- *           以获得家长的认可和实际的奖励物品。
- *
- * 流程步骤:
- *   1. 孩子创建心愿(如"想要一套科学实验套装")
- *   2. 家长查看心愿并设定所需积分(如 500 积分)
- *   3. 孩子通过完成任务积累积分后,申请兑换心愿
- *   4. 家长审批通过,系统自动扣除积分
- *   5. 家长购买物品后标记"已购买"
- *   6. 孩子确认收货,心愿流程完成
- *
- * 关键里程碑:
- *   - [Milestone-1] 心愿创建成功,获得心愿ID
- *   - [Milestone-2] 家长定价成功,心愿状态变更为"已定价"
- *   - [Milestone-3] 兑换申请提交,状态变更为"兑换中"
- *   - [Milestone-4] 家长审批通过,积分立即扣减
- *   - [Milestone-5] 标记已购买,等待孩子确认
- *   - [Milestone-6] 孩子确认收货,心愿完成
- * ================================================================
- */
-@SpringBootTest
-public class WishExchangeFlowTest {
-
-    @Resource
-    private WishController wishController;
-
-    @MockBean
-    private WishService wishService;
-
-    @MockBean
-    private PointsService pointsService;
-
-    @MockBean
-    private WishMapper wishMapper;
-
-    // ========== 测试数据 ==========
-
-    private static final Long CHILD_USER_ID = 2001L;
-    private static final Long PARENT_USER_ID = 1001L;
-    private static final Long FAMILY_ID = 3001L;
-    private static final Long WISH_ID = 1L;
-    private static final String WISH_TITLE = "科学实验套装";
-    private static final Integer POINTS_REQUIRED = 500;
-
-    // ========== 场景1:孩子创建心愿 ==========
-
-    /**
-     * 场景:孩子创建一个新的心愿
-     * 角色:孩子
-     * 触发条件:孩子点击"创建心愿"并填写表单
-     */
-    @Test
-    @DisplayName("[场景1] 孩子创建心愿 - 期望心愿创建成功")
-    void childCreatesWish_Success() {
-        // === Given:孩子填写了心愿信息 ===
-        CreateWishDTO createDTO = new CreateWishDTO();
-        createDTO.setTitle(WISH_TITLE);
-        createDTO.setDescription("包含50个实验的科学实验套装");
-        createDTO.setImageUrl("https://example.com/science-kit.jpg");
-        createDTO.setLinkUrl("https://shop.example.com/science-kit");
-        createDTO.setEstimatedPrice(29900L); // 299元
-
-        when(wishService.createByChild(eq(CHILD_USER_ID), any(CreateWishDTO.class)))
-                .thenReturn(WISH_ID);
-
-        // === When:孩子提交创建心愿表单 ===
-        Result<Long> result = wishController.createWish(
-                CHILD_USER_ID, "child", createDTO);
-
-        // === Then:Milestone-1 - 心愿创建成功 ===
-        assertEquals(200, result.getCode());
-        assertNotNull(result.getData());
-        assertEquals(WISH_ID, result.getData());
-        verify(wishService).createByChild(eq(CHILD_USER_ID), any(CreateWishDTO.class));
-    }
-
-    // ========== 场景2:家长定价 ==========
-
-    /**
-     * 场景:家长为孩子的心愿设定所需积分
-     * 角色:家长
-     * 触发条件:家长打开心愿详情,决定设定多少积分可兑换
-     */
-    @Test
-    @DisplayName("[场景2] 家长设定心愿积分 - 期望积分设定成功且状态更新")
-    void parentSetsWishPrice_Success() {
-        // === Given:家长决定设定 500 积分 ===
-        Map<String, Object> priceRequest = new HashMap<>();
-        priceRequest.put("pointsRequired", POINTS_REQUIRED);
-
-        when(wishService.setPrice(eq(WISH_ID), eq(PARENT_USER_ID), eq(POINTS_REQUIRED)))
-                .thenReturn(true);
-
-        // === When:家长提交定价 ===
-        Result<Boolean> result = wishController.setPrice(
-                WISH_ID, PARENT_USER_ID, priceRequest);
-
-        // === Then:Milestone-2 - 定价成功 ===
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-        verify(wishService).setPrice(eq(WISH_ID), eq(PARENT_USER_ID), eq(POINTS_REQUIRED));
-    }
-
-    /**
-     * 场景:家长设定的积分值为负数或零
-     * 角色:家长
-     * 触发条件:表单校验未通过
-     */
-    @Test
-    @DisplayName("[场景2b] 家长设定无效积分值 - 期望返回错误提示")
-    void parentSetsInvalidPrice_Fails() {
-        // === Given:设定了无效的积分值 ===
-        Map<String, Object> priceRequest = new HashMap<>();
-        priceRequest.put("pointsRequired", 0); // 无效值
-
-        // === When:尝试提交定价 ===
-        Result<Boolean> result = wishController.setPrice(
-                WISH_ID, PARENT_USER_ID, priceRequest);
-
-        // === Then:返回错误提示 ===
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("有效") || result.getMessage().contains("大于0"));
-    }
-
-    // ========== 场景3:孩子申请兑换 ==========
-
-    /**
-     * 场景:孩子积累足够积分后,申请兑换心愿
-     * 角色:孩子
-     * 触发条件:孩子点击心愿的"申请兑换"按钮
-     */
-    @Test
-    @DisplayName("[场景3] 孩子申请兑换心愿 - 期望兑换申请提交成功")
-    void childRequestsExchange_Success() {
-        // === Given:孩子已积累足够积分 ===
-        when(wishService.requestExchange(eq(WISH_ID), eq(CHILD_USER_ID)))
-                .thenReturn(true);
-
-        // === When:孩子点击"申请兑换" ===
-        Result<Boolean> result = wishController.requestExchange(WISH_ID, CHILD_USER_ID);
-
-        // === Then:Milestone-3 - 兑换申请提交成功 ===
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-        verify(wishService).requestExchange(eq(WISH_ID), eq(CHILD_USER_ID));
-    }
-
-    /**
-         * 场景:孩子积分不足时尝试兑换
-     * 角色:孩子
-     * 触发条件:孩子积分不足以兑换该心愿
-     */
-    @Test
-    @DisplayName("[场景3b] 积分不足时申请兑换 - 期望返回错误提示")
-    void childRequestsExchangeWithInsufficientPoints_Fails() {
-        // === Given:孩子积分不足 ===
-        when(wishService.requestExchange(eq(WISH_ID), eq(CHILD_USER_ID)))
-                .thenThrow(new RuntimeException("积分不足,当前积分:200,需要:500"));
-
-        // === When:孩子尝试兑换 ===
-        Result<Boolean> result = wishController.requestExchange(WISH_ID, CHILD_USER_ID);
-
-        // === Then:返回积分不足提示 ===
-        assertEquals(500, result.getCode());
-        assertTrue(result.getMessage().contains("积分不足"));
-    }
-
-    // ========== 场景4:家长审批兑换 ==========
-
-    /**
-     * 场景:家长审批通过孩子的兑换申请,积分立即扣除
-     * 角色:家长
-     * 触发条件:家长查看兑换申请并点击"批准"
-     */
-    @Test
-    @DisplayName("[场景4] 家长审批通过兑换 - 期望审批成功且积分扣除")
-    void parentApprovesExchange_Success() {
-        // === Given:家长同意孩子的兑换申请 ===
-        Map<String, Object> approveRequest = new HashMap<>();
-        approveRequest.put("approved", true);
-
-        when(wishService.approveExchange(eq(WISH_ID), eq(PARENT_USER_ID), eq(true)))
-                .thenReturn(true);
-        when(pointsService.deductForWish(eq(CHILD_USER_ID), eq(POINTS_REQUIRED)))
-                .thenReturn(true);
-
-        // === When:家长点击"批准" ===
-        Result<Boolean> result = wishController.approveExchange(
-                WISH_ID, PARENT_USER_ID, approveRequest);
-
-        // === Then:Milestone-4 - 审批通过 + Milestone-5 积分扣减 ===
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-        verify(wishService).approveExchange(eq(WISH_ID), eq(PARENT_USER_ID), eq(true));
-    }
-
-    /**
-     * 场景:家长拒绝孩子的兑换申请
-     * 角色:家长
-     * 触发条件:家长认为该心愿不合适,点击"拒绝"
-     */
-    @Test
-    @DisplayName("[场景4b] 家长拒绝兑换申请 - 期望心愿状态回退")
-    void parentRejectsExchange_Success() {
-        // === Given:家长拒绝兑换申请 ===
-        Map<String, Object> approveRequest = new HashMap<>();
-        approveRequest.put("approved", false);
-        approveRequest.put("reason", "本月预算已用完,下个月再兑换好吗?");
-
-        when(wishService.approveExchange(eq(WISH_ID), eq(PARENT_USER_ID), eq(false)))
-                .thenReturn(true);
-
-        // === When:家长点击"拒绝" ===
-        Result<Boolean> result = wishController.approveExchange(
-                WISH_ID, PARENT_USER_ID, approveRequest);
-
-        // === Then:拒绝成功,心愿状态回退 ===
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-        verify(wishService).approveExchange(eq(WISH_ID), eq(PARENT_USER_ID), eq(false));
-    }
-
-    // ========== 场景5:标记已购买 ==========
-
-    /**
-     * 场景:家长购买物品后标记心愿为"已购买"
-     * 角色:家长
-     * 触发条件:家长完成购买操作
-     */
-    @Test
-    @DisplayName("[场景5] 家长标记心愿已购买 - 期望状态变更为待收货")
-    void parentMarksFulfilled_Success() {
-        // === Given:家长已完成购买 ===
-        when(wishService.markFulfilled(eq(WISH_ID), eq(PARENT_USER_ID)))
-                .thenReturn(true);
-
-        // === When:家长点击"已购买" ===
-        Result<Boolean> result = wishController.markFulfilled(WISH_ID, PARENT_USER_ID);
-
-        // === Then:Milestone-5 - 标记成功 ===
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-        verify(wishService).markFulfilled(eq(WISH_ID), eq(PARENT_USER_ID));
-    }
-
-    // ========== 场景6:孩子确认收货 ==========
-
-    /**
-     * 场景:孩子收到物品后确认收货,心愿流程完成
-     * 角色:孩子
-     * 触发条件:孩子收到实物并确认无误
-     */
-    @Test
-    @DisplayName("[场景6] 孩子确认收货 - 期望心愿流程完成")
-    void childConfirmsReceived_Success() {
-        // === Given:孩子已收到物品 ===
-        when(wishService.confirmReceived(eq(WISH_ID), eq(CHILD_USER_ID)))
-                .thenReturn(true);
-
-        // === When:孩子点击"确认收货" ===
-        Result<Boolean> result = wishController.confirmReceived(WISH_ID, CHILD_USER_ID);
-
-        // === Then:Milestone-6 - 心愿完成 ===
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-        verify(wishService).confirmReceived(eq(WISH_ID), eq(CHILD_USER_ID));
-    }
-
-    // ========== 场景7:完整心愿流程(端到端)============
-
-    /**
-     * 场景:完整的心愿从创建到完成的整个生命周期
-     * 角色:孩子 → 家长 → 孩子
-     * 触发条件:心愿的完整业务流程
-     */
-    @Test
-    @DisplayName("[场景7] 完整心愿生命周期 - 期望全流程成功")
-    void completeWishLifecycle_Success() {
-        // === Step 1:孩子创建心愿 ===
-        CreateWishDTO createDTO = new CreateWishDTO();
-        createDTO.setTitle("一本科学杂志");
-        createDTO.setEstimatedPrice(3000L);
-
-        Long newWishId = 2L;
-        when(wishService.createByChild(eq(CHILD_USER_ID), any(CreateWishDTO.class)))
-                .thenReturn(newWishId);
-
-        Result<Long> createResult = wishController.createWish(
-                CHILD_USER_ID, "child", createDTO);
-        assertEquals(200, createResult.getCode());
-        assertEquals(newWishId, createResult.getData());
-
-        // === Step 2:家长定价 ===
-        Map<String, Object> priceRequest = new HashMap<>();
-        priceRequest.put("pointsRequired", 100);
-
-        when(wishService.setPrice(eq(newWishId), eq(PARENT_USER_ID), eq(100)))
-                .thenReturn(true);
-
-        Result<Boolean> priceResult = wishController.setPrice(
-                newWishId, PARENT_USER_ID, priceRequest);
-        assertEquals(200, priceResult.getCode());
-        assertTrue(priceResult.getData());
-
-        // === Step 3:孩子申请兑换 ===
-        when(wishService.requestExchange(eq(newWishId), eq(CHILD_USER_ID)))
-                .thenReturn(true);
-
-        Result<Boolean> exchangeResult = wishController.requestExchange(newWishId, CHILD_USER_ID);
-        assertEquals(200, exchangeResult.getCode());
-        assertTrue(exchangeResult.getData());
-
-        // === Step 4:家长审批通过 ===
-        Map<String, Object> approveRequest = new HashMap<>();
-        approveRequest.put("approved", true);
-
-        when(wishService.approveExchange(eq(newWishId), eq(PARENT_USER_ID), eq(true)))
-                .thenReturn(true);
-
-        Result<Boolean> approveResult = wishController.approveExchange(
-                newWishId, PARENT_USER_ID, approveRequest);
-        assertEquals(200, approveResult.getCode());
-        assertTrue(approveResult.getData());
-
-        // === Step 5:家长标记已购买 ===
-        when(wishService.markFulfilled(eq(newWishId), eq(PARENT_USER_ID)))
-                .thenReturn(true);
-
-        Result<Boolean> fulfillResult = wishController.markFulfilled(newWishId, PARENT_USER_ID);
-        assertEquals(200, fulfillResult.getCode());
-        assertTrue(fulfillResult.getData());
-
-        // === Step 6:孩子确认收货 ===
-        when(wishService.confirmReceived(eq(newWishId), eq(CHILD_USER_ID)))
-                .thenReturn(true);
-
-        Result<Boolean> confirmResult = wishController.confirmReceived(newWishId, CHILD_USER_ID);
-        assertEquals(200, confirmResult.getCode());
-        assertTrue(confirmResult.getData());
-    }
-
-    // ========== 场景8:家长拒绝心愿 ==========
-
-    /**
-     * 场景:家长认为某个心愿不合适,直接拒绝
-     * 角色:家长
-     * 触发条件:家长点击"拒绝"并填写原因
-     */
-    @Test
-    @DisplayName("[场景8] 家长直接拒绝心愿 - 期望心愿被关闭")
-    void parentRejectsWish_Success() {
-        // === Given:家长决定拒绝该心愿 ===
-        Map<String, String> rejectRequest = new HashMap<>();
-        rejectRequest.put("reason", "这套书家里已经有了,换个其他的吧");
-
-        when(wishService.rejectWish(eq(WISH_ID), eq(PARENT_USER_ID), anyString()))
-                .thenReturn(true);
-
-        // === When:家长点击"拒绝" ===
-        Result<Boolean> result = wishController.rejectWish(
-                WISH_ID, PARENT_USER_ID, rejectRequest);
-
-        // === Then:心愿被关闭 ===
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-        verify(wishService).rejectWish(eq(WISH_ID), eq(PARENT_USER_ID), anyString());
-    }
-
-    // ========== 场景9:孩子取消心愿 ==========
-
-    /**
-     * 场景:孩子改变主意,主动取消心愿
-     * 角色:孩子
-     * 触发条件:孩子点击"取消心愿"
-     */
-    @Test
-    @DisplayName("[场景9] 孩子取消心愿 - 期望心愿被取消")
-    void childCancelsWish_Success() {
-        // === Given:孩子改变主意 ===
-        Map<String, String> cancelRequest = new HashMap<>();
-        cancelRequest.put("reason", "想了想还是不要了");
-
-        when(wishService.cancelWish(eq(WISH_ID), eq(CHILD_USER_ID), anyString()))
-                .thenReturn(true);
-
-        // === When:孩子点击"取消" ===
-        Result<Boolean> result = wishController.cancelWish(
-                WISH_ID, CHILD_USER_ID, cancelRequest);
-
-        // === Then:心愿被取消 ===
-        assertEquals(200, result.getCode());
-        assertTrue(result.getData());
-        verify(wishService).cancelWish(eq(WISH_ID), eq(CHILD_USER_ID), anyString());
-    }
-
-    // ========== Helper Methods ==========
-
-    private WishDTO createWishDTO(Long id, String title, String status) {
-        WishDTO dto = new WishDTO();
-        dto.setId(id);
-        dto.setTitle(title);
-        dto.setStatus(status);
-        dto.setPointsRequired(POINTS_REQUIRED);
-        return dto;
-    }
-}

+ 0 - 327
cfc-backend/src/test/java/com/etotem/cfc/service/ArticleServiceTest.java

@@ -1,327 +0,0 @@
-package com.etotem.cfc.service;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.etotem.cfc.entity.Article;
-import com.etotem.cfc.mapper.ArticleMapper;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import javax.annotation.Resource;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-@SpringBootTest
-public class ArticleServiceTest {
-
-    @Resource
-    private ArticleService articleService;
-
-    @MockBean
-    private ArticleMapper articleMapper;
-
-    @MockBean
-    private ArticlePermissionService articlePermissionService;
-
-    @MockBean
-    private ArticleCategoryService articleCategoryService;
-
-    private Article mockArticle(Long id, String title, String status, String visibility) {
-        Article a = new Article();
-        a.setId(id);
-        a.setTitle(title);
-        a.setSummary("摘要");
-        a.setContent("<p>内容</p>");
-        a.setAuthor("测试");
-        a.setStatus(status);
-        a.setVisibility(visibility);
-        a.setCategoryId(1L);
-        a.setIsFeatured(0);
-        a.setViewCount(5);
-        a.setCreatedBy(1L);
-        return a;
-    }
-
-    // ==================== getPublicList ====================
-
-    @Test
-    public void getPublicList_OnlyPublished() {
-        List<Article> allArticles = Arrays.asList(
-            mockArticle(1L, "已发布", "published", "public"),
-            mockArticle(2L, "草稿", "draft", "public")
-        );
-
-        // Mock mapper to return all articles (real filtering happens via wrapper)
-        when(articleMapper.selectPage(any(Page.class), any(LambdaQueryWrapper.class)))
-            .thenAnswer(invocation -> {
-                Page<Article> page = invocation.getArgument(0);
-                page.setRecords(allArticles);
-                page.setTotal(2);
-                return page;
-            });
-
-        // Permission service allows all visible ones
-        when(articlePermissionService.filterVisible(anyList(), isNull(), isNull(), isNull()))
-            .thenReturn(Arrays.asList(allArticles.get(0))); // Only published
-
-        Page<Article> result = articleService.getPublicList(null, null, null, 1, 10, null, null, null);
-        assertEquals(1, result.getRecords().size());
-        assertEquals("已发布", result.getRecords().get(0).getTitle());
-    }
-
-    @Test
-    public void getPublicList_Empty() {
-        when(articleMapper.selectPage(any(Page.class), any(LambdaQueryWrapper.class)))
-            .thenAnswer(invocation -> {
-                Page<Article> page = invocation.getArgument(0);
-                page.setRecords(Collections.emptyList());
-                page.setTotal(0);
-                return page;
-            });
-        when(articlePermissionService.filterVisible(anyList(), isNull(), isNull(), isNull()))
-            .thenReturn(Collections.emptyList());
-
-        Page<Article> result = articleService.getPublicList(null, null, null, 1, 10, null, null, null);
-        assertTrue(result.getRecords().isEmpty());
-        assertEquals(0, result.getTotal());
-    }
-
-    // ==================== getDetail ====================
-
-    @Test
-    public void getDetail_Success() {
-        Article article = mockArticle(1L, "详情文章", "published", "public");
-        when(articleMapper.selectById(1L)).thenReturn(article);
-        when(articlePermissionService.isVisible(article, null, null, null)).thenReturn(true);
-
-        Article result = articleService.getDetail(1L, null, null, null);
-        assertNotNull(result);
-        assertEquals("详情文章", result.getTitle());
-    }
-
-    @Test
-    public void getDetail_NotFound() {
-        when(articleMapper.selectById(999L)).thenReturn(null);
-
-        Article result = articleService.getDetail(999L, null, null, null);
-        assertNull(result);
-    }
-
-    @Test
-    public void getDetail_NotPublished() {
-        Article article = mockArticle(1L, "草稿", "draft", "public");
-        when(articleMapper.selectById(1L)).thenReturn(article);
-
-        Article result = articleService.getDetail(1L, null, null, null);
-        assertNull(result);
-    }
-
-    @Test
-    public void getDetail_NoPermission() {
-        Article article = mockArticle(1L, "私密文章", "published", "private");
-        when(articleMapper.selectById(1L)).thenReturn(article);
-        when(articlePermissionService.isVisible(article, null, null, null)).thenReturn(false);
-
-        Article result = articleService.getDetail(1L, null, null, null);
-        assertNull(result);
-    }
-
-    // ==================== getFeatured ====================
-
-    @Test
-    public void getFeatured_Success() {
-        List<Article> featured = Arrays.asList(
-            mockArticle(1L, "精选1", "published", "public"),
-            mockArticle(2L, "精选2", "published", "public")
-        );
-
-        when(articleMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(featured);
-        when(articlePermissionService.filterVisible(featured, null, null, null)).thenReturn(featured);
-
-        List<Article> result = articleService.getFeatured(5, null, null, null);
-        assertEquals(2, result.size());
-    }
-
-    @Test
-    public void getFeatured_Limit() {
-        List<Article> featured = Arrays.asList(
-            mockArticle(1L, "精选1", "published", "public"),
-            mockArticle(2L, "精选2", "published", "public"),
-            mockArticle(3L, "精选3", "published", "public")
-        );
-
-        when(articleMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(featured);
-        when(articlePermissionService.filterVisible(featured, null, null, null)).thenReturn(featured);
-
-        List<Article> result = articleService.getFeatured(2, null, null, null);
-        assertEquals(2, result.size());
-    }
-
-    @Test
-    public void getFeatured_Empty() {
-        when(articleMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(Collections.emptyList());
-        when(articlePermissionService.filterVisible(anyList(), isNull(), isNull(), isNull()))
-            .thenReturn(Collections.emptyList());
-
-        List<Article> result = articleService.getFeatured(5, null, null, null);
-        assertTrue(result.isEmpty());
-    }
-
-    // ==================== recordRead ====================
-
-    @Test
-    public void recordRead_IncrementsViewCount() {
-        doAnswer(invocation -> {
-            // Verify the update wrapper has setSql for view_count increment
-            return 1;
-        }).when(articleMapper).update(any(), any(LambdaQueryWrapper.class));
-
-        articleService.recordRead(1L, null, null, 30);
-        verify(articleMapper, times(1)).update(any(), any());
-    }
-
-    // ==================== getAdminList ====================
-
-    @Test
-    public void getAdminList_All() {
-        when(articleMapper.selectPage(any(Page.class), any(LambdaQueryWrapper.class)))
-            .thenAnswer(invocation -> {
-                Page<Article> page = invocation.getArgument(0);
-                page.setRecords(Arrays.asList(mockArticle(1L, "管理可见", "published", "public")));
-                page.setTotal(1);
-                return page;
-            });
-
-        Page<Article> result = articleService.getAdminList(null, null, null, null, null, null, null, null, 1, 20);
-        assertEquals(1, result.getRecords().size());
-    }
-
-    @Test
-    public void getAdminList_WithStatusFilter() {
-        when(articleMapper.selectPage(any(Page.class), any(LambdaQueryWrapper.class)))
-            .thenAnswer(invocation -> {
-                Page<Article> page = invocation.getArgument(0);
-                page.setRecords(Arrays.asList(mockArticle(1L, "草稿文章", "draft", "public")));
-                page.setTotal(1);
-                return page;
-            });
-
-        Page<Article> result = articleService.getAdminList("draft", null, null, null, null, null, null, null, 1, 20);
-        assertEquals(1, result.getRecords().size());
-    }
-
-    // ==================== create ====================
-
-    @Test
-    public void create_SetsInitialValues() {
-        Article article = mockArticle(null, "新文章", "draft", "public");
-        when(articleMapper.insert(any(Article.class))).thenReturn(1);
-
-        articleService.create(article, 1L);
-
-        verify(articleMapper).insert(argThat(a -> {
-            assertNull(a.getId());
-            assertEquals(1L, a.getCreatedBy().longValue());
-            assertEquals(0, a.getViewCount().intValue());
-            assertNotNull(a.getCreatedAt());
-            assertNotNull(a.getUpdatedAt());
-            return true;
-        }));
-    }
-
-    @Test
-    public void create_PublishedSetsPublishTime() {
-        Article article = mockArticle(null, "直接发布", "published", "public");
-        when(articleMapper.insert(any(Article.class))).thenReturn(1);
-
-        articleService.create(article, 1L);
-
-        verify(articleMapper).insert(argThat(a -> {
-            assertNotNull(a.getPublishedAt());
-            return true;
-        }));
-    }
-
-    // ==================== update ====================
-
-    @Test
-    public void update_SetsUpdatedAt() {
-        Article article = mockArticle(1L, "更新", "published", "public");
-        when(articleMapper.updateById(any(Article.class))).thenReturn(1);
-
-        articleService.update(article);
-        verify(articleMapper).updateById(argThat(a -> {
-            assertNotNull(a.getUpdatedAt());
-            return true;
-        }));
-    }
-
-    // ==================== delete ====================
-
-    @Test
-    public void delete_DeletesById() {
-        articleService.delete(1L);
-        verify(articleMapper).deleteById(1L);
-    }
-
-    // ==================== toggleStatus ====================
-
-    @Test
-    public void toggleStatus_Publish() {
-        Article article = mockArticle(1L, "发布", "draft", "public");
-        when(articleMapper.selectById(1L)).thenReturn(article);
-        when(articleMapper.updateById(any(Article.class))).thenReturn(1);
-
-        articleService.toggleStatus(1L, "published");
-        assertEquals("published", article.getStatus());
-        assertNotNull(article.getUpdatedAt());
-        assertNotNull(article.getPublishedAt());
-    }
-
-    @Test
-    public void toggleStatus_Draft() {
-        Article article = mockArticle(1L, "下架", "published", "public");
-        article.setPublishedAt(new Date());
-        when(articleMapper.selectById(1L)).thenReturn(article);
-        when(articleMapper.updateById(any(Article.class))).thenReturn(1);
-
-        articleService.toggleStatus(1L, "draft");
-        assertEquals("draft", article.getStatus());
-    }
-
-    @Test
-    public void toggleStatus_ArticleNotFound() {
-        when(articleMapper.selectById(999L)).thenReturn(null);
-
-        articleService.toggleStatus(999L, "published");
-        verify(articleMapper, never()).updateById(any());
-    }
-
-    // ==================== toggleFeatured ====================
-
-    @Test
-    public void toggleFeatured_SetFeatured() {
-        Article article = mockArticle(1L, "精选", "published", "public");
-        when(articleMapper.selectById(1L)).thenReturn(article);
-
-        articleService.toggleFeatured(1L, 1);
-        assertEquals(1, article.getIsFeatured().intValue());
-        assertNotNull(article.getUpdatedAt());
-        verify(articleMapper).updateById(article);
-    }
-
-    @Test
-    public void toggleFeatured_RemoveFeatured() {
-        Article article = mockArticle(1L, "取消精选", "published", "public");
-        article.setIsFeatured(1);
-        when(articleMapper.selectById(1L)).thenReturn(article);
-
-        articleService.toggleFeatured(1L, 0);
-        assertEquals(0, article.getIsFeatured().intValue());
-        verify(articleMapper).updateById(article);
-    }
-}

+ 0 - 270
cfc-backend/src/test/java/com/etotem/cfc/service/FamilyChallengeServiceTest.java

@@ -1,270 +0,0 @@
-package com.etotem.cfc.service;
-
-import com.etotem.cfc.common.Result;
-import com.etotem.cfc.entity.FamilyChallenge;
-import com.etotem.cfc.entity.FamilyChallengeParticipant;
-import com.etotem.cfc.entity.FamilyChallengeProgress;
-import com.etotem.cfc.entity.FamilyMember;
-import com.etotem.cfc.mapper.FamilyChallengeMapper;
-import com.etotem.cfc.mapper.FamilyChallengeParticipantMapper;
-import com.etotem.cfc.mapper.FamilyChallengeProgressMapper;
-import com.etotem.cfc.mapper.FamilyMemberMapper;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Date;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyList;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class FamilyChallengeServiceTest {
-
-    @Mock private FamilyChallengeMapper familyChallengeMapper;
-    @Mock private FamilyChallengeProgressMapper familyChallengeProgressMapper;
-    @Mock private FamilyChallengeParticipantMapper familyChallengeParticipantMapper;
-    @Mock private FamilyMemberMapper familyMemberMapper;
-    @Mock private HealthScoreService healthScoreService;
-    @Mock private PointsService pointsService;
-    @Mock private ChallengeScoreService challengeScoreService;
-    @InjectMocks private FamilyChallengeService service;
-
-    @BeforeEach
-    void setUp() {
-        MockitoAnnotations.openMocks(this);
-        when(familyChallengeParticipantMapper.selectList(any())).thenReturn(java.util.Collections.emptyList());
-    }
-
-    @Test
-    void updateProgress_shouldRejectDuplicateCheckinSameDay() {
-        FamilyChallenge challenge = new FamilyChallenge();
-        challenge.setId(1L);
-        challenge.setFamilyId(10L);
-        challenge.setStatus("active");
-        challenge.setTargetMode("aggregate");
-        challenge.setTargetValue(300);
-        challenge.setEndDate(new Date(System.currentTimeMillis() + 86400000L * 7));
-
-        FamilyChallengeProgress existing = new FamilyChallengeProgress();
-        existing.setChallengeId(1L);
-        existing.setChildId(100L);
-        existing.setProgressValue(5);
-        existing.setUpdatedAt(new Date());
-
-        FamilyChallengeParticipant participant = new FamilyChallengeParticipant();
-        participant.setChallengeId(1L);
-        participant.setMemberId(100L);
-        participant.setStatus("agreed");
-
-        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
-        when(familyChallengeProgressMapper.selectOne(any())).thenReturn(existing);
-        when(familyMemberMapper.selectCount(any())).thenReturn(1L);
-        when(familyChallengeParticipantMapper.selectOne(any())).thenReturn(participant);
-
-        Result<Void> result = service.updateProgress(1L, 100L, 1);
-
-        assertEquals(Integer.valueOf(500), result.getCode());
-        verify(familyChallengeProgressMapper, never()).updateById(any());
-    }
-
-    @Test
-    void updateProgress_shouldRejectWhenChallengeNotActive() {
-        FamilyChallenge challenge = new FamilyChallenge();
-        challenge.setId(1L);
-        challenge.setFamilyId(10L);
-        challenge.setStatus("completed");
-        challenge.setTargetMode("aggregate");
-        challenge.setTargetValue(300);
-        challenge.setEndDate(new Date(System.currentTimeMillis() + 86400000L * 7));
-
-        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
-
-        Result<Void> result = service.updateProgress(1L, 100L, 1);
-
-        assertEquals(Integer.valueOf(500), result.getCode());
-        verify(familyChallengeProgressMapper, never()).insert(any());
-        verify(familyChallengeProgressMapper, never()).updateById(any());
-    }
-
-    @Test
-    void checkAndSettle_shouldGrantPointsWhenCompleted() {
-        FamilyChallenge challenge = new FamilyChallenge();
-        challenge.setId(1L);
-        challenge.setFamilyId(10L);
-        challenge.setStatus("active");
-        challenge.setTargetMode("aggregate");
-        challenge.setTargetValue(10);
-        challenge.setRewardPoints(50);
-        challenge.setEndDate(new Date(System.currentTimeMillis() - 86400000L));
-
-        FamilyChallengeProgress p = new FamilyChallengeProgress();
-        p.setChallengeId(1L);
-        p.setChildId(100L);
-        p.setProgressValue(12);
-        p.setCompleted(false);
-
-        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
-        when(familyChallengeProgressMapper.selectList(any())).thenReturn(java.util.Arrays.asList(p));
-        when(familyMemberMapper.selectList(any())).thenReturn(java.util.Collections.emptyList());
-        when(familyChallengeMapper.update(any(), any())).thenReturn(1);
-
-        service.settleChallenge(1L);
-
-        verify(familyChallengeMapper).update(any(), any());
-        verify(familyChallengeProgressMapper).updateById(argThat(p2 -> Boolean.TRUE.equals(p2.getCompleted())));
-        verify(pointsService).awardSystemPoints(eq(100L), eq(50), anyString());
-    }
-
-    @Test
-    void getActiveChallenges_shouldSettleExpiredChallenges() {
-        FamilyChallenge expired = new FamilyChallenge();
-        expired.setId(2L);
-        expired.setFamilyId(10L);
-        expired.setStatus("active");
-        expired.setTargetMode("aggregate");
-        expired.setTargetValue(10);
-        expired.setEndDate(new Date(System.currentTimeMillis() - 86400000L));
-
-        when(familyChallengeMapper.selectList(any())).thenReturn(java.util.Arrays.asList(expired));
-        when(familyChallengeProgressMapper.selectList(any())).thenReturn(java.util.Collections.emptyList());
-        when(familyMemberMapper.selectList(any())).thenReturn(java.util.Collections.emptyList());
-        when(familyChallengeMapper.update(any(), any())).thenReturn(1);
-
-        service.getActiveChallenges(10L, null);
-
-        verify(familyChallengeMapper).update(any(), any());
-    }
-
-    @Test
-    void getTemplates_shouldReturnAllTemplatesWithParsedRewardPoints() {
-        java.util.List<java.util.Map<String, Object>> templates = service.getTemplates();
-
-        assertEquals(7, templates.size());
-        for (java.util.Map<String, Object> t : templates) {
-            assertTrue(t.get("rewardPoints") instanceof Integer, "rewardPoints 必须可解析为 Integer");
-            assertTrue(t.get("durationDays") instanceof Integer, "durationDays 必须可解析为 Integer");
-            assertTrue(t.get("targetValue") instanceof Integer, "targetValue 必须可解析为 Integer");
-            assertTrue(t.get("targetMode") instanceof String, "targetMode 必须存在");
-        }
-        java.util.Map<String, Object> first = templates.get(0);
-        assertEquals("full_checkin", first.get("type"));
-        assertEquals("全员打卡挑战", first.get("title"));
-        assertEquals(Integer.valueOf(3), first.get("durationDays"));
-        assertEquals(Integer.valueOf(3), first.get("targetValue"));
-        assertEquals(Integer.valueOf(50), first.get("rewardPoints"));
-        assertEquals("all_members", first.get("targetMode"));
-        java.util.Map<String, Object> sports = templates.get(1);
-        assertEquals("sports", sports.get("type"));
-        assertEquals("aggregate", sports.get("targetMode"));
-        assertEquals(Integer.valueOf(300), sports.get("targetValue"));
-        assertEquals(Integer.valueOf(100), sports.get("rewardPoints"));
-    }
-
-    @Test
-    void respondChallenge_agree_shouldTransitionToActiveWhenAllAgreed() {
-        FamilyChallenge challenge = new FamilyChallenge();
-        challenge.setId(1L);
-        challenge.setFamilyId(10L);
-        challenge.setStatus("pending");
-        challenge.setTargetMode("aggregate");
-        challenge.setTargetValue(300);
-        challenge.setCreatorId(9L);
-
-        FamilyChallengeParticipant p = new FamilyChallengeParticipant();
-        p.setId(1L);
-        p.setChallengeId(1L);
-        p.setMemberId(100L);
-        p.setStatus("pending");
-
-        FamilyChallengeParticipant initiator = new FamilyChallengeParticipant();
-        initiator.setId(2L);
-        initiator.setChallengeId(1L);
-        initiator.setMemberId(200L);
-        initiator.setStatus("agreed");
-
-        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
-        when(familyChallengeParticipantMapper.selectOne(any())).thenReturn(p);
-        when(familyChallengeParticipantMapper.selectList(any()))
-                .thenReturn(java.util.Arrays.asList(initiator, p));
-
-        Result<Void> result = service.respondChallenge(1L, 100L, "agree");
-
-        assertEquals(Integer.valueOf(200), result.getCode());
-        verify(challengeScoreService).applyAgree(eq(10L), eq(100L), anyList(), eq(1L));
-        verify(familyChallengeParticipantMapper).updateById(argThat(pp -> "agreed".equals(pp.getStatus())));
-        verify(familyChallengeMapper).updateById(argThat(c -> "active".equals(c.getStatus())));
-    }
-
-    @Test
-    void respondChallenge_reject_shouldCancelWhenOnlyInitiatorLeft() {
-        FamilyChallenge challenge = new FamilyChallenge();
-        challenge.setId(1L);
-        challenge.setFamilyId(10L);
-        challenge.setStatus("pending");
-        challenge.setTargetMode("aggregate");
-        challenge.setTargetValue(300);
-        challenge.setCreatorId(9L);
-
-        FamilyChallengeParticipant p = new FamilyChallengeParticipant();
-        p.setId(1L);
-        p.setChallengeId(1L);
-        p.setMemberId(100L);
-        p.setStatus("pending");
-
-        FamilyChallengeParticipant initiator = new FamilyChallengeParticipant();
-        initiator.setId(2L);
-        initiator.setChallengeId(1L);
-        initiator.setMemberId(200L);
-        initiator.setStatus("agreed");
-
-        FamilyMember member = new FamilyMember();
-        member.setId(200L);
-        member.setUserId(9L);
-
-        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
-        when(familyChallengeParticipantMapper.selectOne(any())).thenReturn(p);
-        when(familyChallengeParticipantMapper.selectList(any()))
-                .thenReturn(java.util.Arrays.asList(initiator, p));
-        when(familyMemberMapper.selectList(any())).thenReturn(java.util.Arrays.asList(member));
-
-        Result<Void> result = service.respondChallenge(1L, 100L, "reject");
-
-        assertEquals(Integer.valueOf(200), result.getCode());
-        verify(challengeScoreService).applyReject(eq(10L), eq(100L), eq(200L), anyList(), eq(1L));
-        verify(familyChallengeMapper).updateById(argThat(c -> "cancelled".equals(c.getStatus())));
-    }
-
-    @Test
-    void respondChallenge_shouldRejectWhenAlreadyProcessed() {
-        FamilyChallenge challenge = new FamilyChallenge();
-        challenge.setId(1L);
-        challenge.setFamilyId(10L);
-        challenge.setStatus("pending");
-        challenge.setTargetMode("aggregate");
-        challenge.setTargetValue(300);
-
-        FamilyChallengeParticipant p = new FamilyChallengeParticipant();
-        p.setId(1L);
-        p.setChallengeId(1L);
-        p.setMemberId(100L);
-        p.setStatus("agreed"); // 已处理过
-
-        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
-        when(familyChallengeParticipantMapper.selectOne(any())).thenReturn(p);
-
-        Result<Void> result = service.respondChallenge(1L, 100L, "agree");
-
-        assertEquals(Integer.valueOf(500), result.getCode());
-        verify(challengeScoreService, never()).applyAgree(any(), any(), any(), any());
-    }
-}

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-e7752fb86d5e1c2a2dbd3fd512d9ac47c848010f
+009f40aa7dfb6a2efbc5c1ec013bde8603f08845

+ 1 - 1
cfc-web/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "cfc-web",
   "name": "cfc-web",
-  "version": "1.0.1243",
+  "version": "1.0.1244",
   "private": true,
   "private": true,
   "scripts": {
   "scripts": {
     "dev": "vue-cli-service serve",
     "dev": "vue-cli-service serve",

+ 13 - 0
cfc-web/public/CHANGELOG-v1.0.md

@@ -4,6 +4,19 @@
 
 
 ---
 ---
 
 
+## v1.0.1244 (2026-08-29)
+
+### Bug 修复
+- 打破 MembershipService↔VirtualPayService 循环依赖
+
+### 其他
+- 在启动期强制互相实例化导致 Spring Boot 2.7 拒绝启动(循环依赖默认禁止)。
+- 解决方案:在 MembershipService 的 VirtualPayService 注入点加 @Lazy,
+- 启动期注入代理,运行时才解析真实 bean,打破循环。
+- 参考:Spring 5.3 的 ResourceElement 支持 lazyLookup,与 @Resource 兼容。
+- 
+
+
 ## v1.0.1243 (2026-08-29)
 ## v1.0.1243 (2026-08-29)
 
 
 ### Bug 修复
 ### Bug 修复

+ 14 - 1
cfc-web/public/CHANGELOG.md

@@ -1,6 +1,6 @@
 # 更新日志
 # 更新日志
 
 
-> 当前版本: v1.0.1243
+> 当前版本: v1.0.1244
 
 
 ## 历史版本
 ## 历史版本
 
 
@@ -8,6 +8,19 @@
 
 
 ---
 ---
 
 
+## v1.0.1244 (2026-08-29)
+
+### Bug 修复
+- 打破 MembershipService↔VirtualPayService 循环依赖
+
+### 其他
+- 在启动期强制互相实例化导致 Spring Boot 2.7 拒绝启动(循环依赖默认禁止)。
+- 解决方案:在 MembershipService 的 VirtualPayService 注入点加 @Lazy,
+- 启动期注入代理,运行时才解析真实 bean,打破循环。
+- 参考:Spring 5.3 的 ResourceElement 支持 lazyLookup,与 @Resource 兼容。
+- 
+
+
 ## v1.0.1243 (2026-08-29)
 ## v1.0.1243 (2026-08-29)
 
 
 ### Bug 修复
 ### Bug 修复