|
|
@@ -0,0 +1,167 @@
|
|
|
+package com.etotem.cfc.controller.admin;
|
|
|
+
|
|
|
+import com.etotem.cfc.entity.SupplySystem;
|
|
|
+import com.etotem.cfc.service.SupplySystemService;
|
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
+import org.mockito.Mock;
|
|
|
+import org.mockito.MockitoAnnotations;
|
|
|
+import org.springframework.http.MediaType;
|
|
|
+import org.springframework.test.util.ReflectionTestUtils;
|
|
|
+import org.springframework.test.web.servlet.MockMvc;
|
|
|
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
|
|
+
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
|
+import static org.mockito.ArgumentMatchers.anyList;
|
|
|
+import static org.mockito.ArgumentMatchers.anyLong;
|
|
|
+import static org.mockito.ArgumentMatchers.anyString;
|
|
|
+import static org.mockito.ArgumentMatchers.eq;
|
|
|
+import static org.mockito.Mockito.mock;
|
|
|
+import static org.mockito.Mockito.never;
|
|
|
+import static org.mockito.Mockito.verify;
|
|
|
+import static org.mockito.Mockito.when;
|
|
|
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
|
|
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
|
|
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
|
|
+
|
|
|
+/**
|
|
|
+ * TDD 覆盖驱动(T38 邀请功能 / 能力键 team.invite.*):
|
|
|
+ * POST /api/admin/supply-team/invite-code、/invite/info、/invite/join 的契约级单测。
|
|
|
+ *
|
|
|
+ * 契约(对应 SupplyTeamController):
|
|
|
+ * - invite-code:systemId 空 → error("systemId不能为空");非成员/管理员 → error("无权操作该团队");
|
|
|
+ * 正常 → generateInviteCode 返回码 + getById 拼装团队信息 → success(data)
|
|
|
+ * - invite/info:inviteCode 空 → error("邀请码不能为空");正常 → getInviteInfo 返回 info → success
|
|
|
+ * - invite/join:inviteCode 空 → error("邀请码不能为空");正常 → joinByInviteCode(code,userId) → success
|
|
|
+ *
|
|
|
+ * 测试不依赖数据库/外部服务:supplySystemService 全 mock;不启 Spring 上下文。
|
|
|
+ */
|
|
|
+public class SupplyTeamControllerInviteTest {
|
|
|
+
|
|
|
+ @Mock private SupplySystemService supplySystemService;
|
|
|
+
|
|
|
+ private MockMvc mockMvc;
|
|
|
+ private SupplyTeamController controller;
|
|
|
+
|
|
|
+ @BeforeEach
|
|
|
+ public void setUp() {
|
|
|
+ MockitoAnnotations.openMocks(this);
|
|
|
+ controller = new SupplyTeamController();
|
|
|
+ ReflectionTestUtils.setField(controller, "supplySystemService", supplySystemService);
|
|
|
+ mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
|
|
|
+ }
|
|
|
+
|
|
|
+ // ---------- invite-code ----------
|
|
|
+ @Test
|
|
|
+ public void inviteCode_missingSystemId_returnsError() throws Exception {
|
|
|
+ Long userId = 1L;
|
|
|
+ String body = "{}";
|
|
|
+ mockMvc.perform(post("/api/admin/supply-team/invite-code")
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .content(body)
|
|
|
+ .requestAttr("userId", userId))
|
|
|
+ .andExpect(status().isOk())
|
|
|
+ .andExpect(jsonPath("$.message").value("systemId不能为空"));
|
|
|
+ verify(supplySystemService, never()).generateInviteCode(anyLong(), anyLong(), anyBoolean());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void inviteCode_notMember_returnsForbidden() throws Exception {
|
|
|
+ Long userId = 1L;
|
|
|
+ Long systemId = 10L;
|
|
|
+ when(supplySystemService.isMemberOrAdmin(systemId, userId)).thenReturn(false);
|
|
|
+ String body = "{\"systemId\":10}";
|
|
|
+ mockMvc.perform(post("/api/admin/supply-team/invite-code")
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .content(body)
|
|
|
+ .requestAttr("userId", userId))
|
|
|
+ .andExpect(status().isOk())
|
|
|
+ .andExpect(jsonPath("$.message").value("无权操作该团队"));
|
|
|
+ verify(supplySystemService, never()).generateInviteCode(anyLong(), anyLong(), anyBoolean());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void inviteCode_success_returnsCodeAndTeam() throws Exception {
|
|
|
+ Long userId = 1L;
|
|
|
+ Long systemId = 10L;
|
|
|
+ when(supplySystemService.isMemberOrAdmin(systemId, userId)).thenReturn(true);
|
|
|
+ when(supplySystemService.generateInviteCode(eq(systemId), eq(userId), anyBoolean())).thenReturn("ABC123");
|
|
|
+ SupplySystem system = mock(SupplySystem.class);
|
|
|
+ when(system.getName()).thenReturn("成长团队A");
|
|
|
+ when(supplySystemService.getById(systemId)).thenReturn(system);
|
|
|
+ String body = "{\"systemId\":10}";
|
|
|
+ mockMvc.perform(post("/api/admin/supply-team/invite-code")
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .content(body)
|
|
|
+ .requestAttr("userId", userId))
|
|
|
+ .andExpect(status().isOk())
|
|
|
+ .andExpect(jsonPath("$.code").value(200))
|
|
|
+ .andExpect(jsonPath("$.data.inviteCode").value("ABC123"))
|
|
|
+ .andExpect(jsonPath("$.data.systemId").value(10))
|
|
|
+ .andExpect(jsonPath("$.data.teamName").value("成长团队A"));
|
|
|
+ verify(supplySystemService).generateInviteCode(eq(systemId), eq(userId), anyBoolean());
|
|
|
+ }
|
|
|
+
|
|
|
+ // ---------- invite/info ----------
|
|
|
+ @Test
|
|
|
+ public void inviteInfo_missingCode_returnsError() throws Exception {
|
|
|
+ String body = "{}";
|
|
|
+ mockMvc.perform(post("/api/admin/supply-team/invite/info")
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .content(body))
|
|
|
+ .andExpect(status().isOk())
|
|
|
+ .andExpect(jsonPath("$.message").value("邀请码不能为空"));
|
|
|
+ verify(supplySystemService, never()).getInviteInfo(anyString());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void inviteInfo_success_returnsInfo() throws Exception {
|
|
|
+ Map<String, Object> info = new HashMap<>();
|
|
|
+ info.put("teamName", "成长团队A");
|
|
|
+ info.put("inviterNickname", "老师小王");
|
|
|
+ when(supplySystemService.getInviteInfo("ABC123")).thenReturn(info);
|
|
|
+ String body = "{\"inviteCode\":\"ABC123\"}";
|
|
|
+ mockMvc.perform(post("/api/admin/supply-team/invite/info")
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .content(body))
|
|
|
+ .andExpect(status().isOk())
|
|
|
+ .andExpect(jsonPath("$.code").value(200))
|
|
|
+ .andExpect(jsonPath("$.data.teamName").value("成长团队A"));
|
|
|
+ verify(supplySystemService).getInviteInfo("ABC123");
|
|
|
+ }
|
|
|
+
|
|
|
+ // ---------- invite/join ----------
|
|
|
+ @Test
|
|
|
+ public void inviteJoin_missingCode_returnsError() throws Exception {
|
|
|
+ Long userId = 1L;
|
|
|
+ String body = "{}";
|
|
|
+ mockMvc.perform(post("/api/admin/supply-team/invite/join")
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .content(body)
|
|
|
+ .requestAttr("userId", userId))
|
|
|
+ .andExpect(status().isOk())
|
|
|
+ .andExpect(jsonPath("$.message").value("邀请码不能为空"));
|
|
|
+ verify(supplySystemService, never()).joinByInviteCode(anyString(), anyLong());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void inviteJoin_success_callsJoin() throws Exception {
|
|
|
+ Long userId = 1L;
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
+ result.put("ok", Boolean.TRUE);
|
|
|
+ result.put("systemId", 10);
|
|
|
+ when(supplySystemService.joinByInviteCode("ABC123", userId)).thenReturn(result);
|
|
|
+ String body = "{\"inviteCode\":\"ABC123\"}";
|
|
|
+ mockMvc.perform(post("/api/admin/supply-team/invite/join")
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .content(body)
|
|
|
+ .requestAttr("userId", userId))
|
|
|
+ .andExpect(status().isOk())
|
|
|
+ .andExpect(jsonPath("$.code").value(200))
|
|
|
+ .andExpect(jsonPath("$.data.ok").value(true));
|
|
|
+ verify(supplySystemService).joinByInviteCode("ABC123", userId);
|
|
|
+ }
|
|
|
+}
|