package com.rongyichuang.judge; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; import java.util.Collections; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.*; /** * 评委模块端到端集成测试 * 模拟完整的前端到后端数据流程: * 1. 前端获取标签列表 * 2. 前端提交评委数据(包含logo.jpg头像) * 3. 后端保存数据到数据库 * 4. 验证数据完整性 */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class JudgeE2EIntegrationTest { @LocalServerPort private int port; @Autowired private TestRestTemplate restTemplate; @Autowired private DataSource dataSource; private JdbcTemplate jdbcTemplate; private ObjectMapper objectMapper = new ObjectMapper(); @Test void testCompleteJudgeCreationFlow() throws Exception { jdbcTemplate = new JdbcTemplate(dataSource); System.out.println("=== 开始完整的评委创建流程测试 ==="); // 步骤1: 前端获取可用标签列表 System.out.println("\n步骤1: 获取标签列表"); List> availableTags = getAvailableTags(); assertTrue(availableTags.size() > 0, "应该有可用的标签"); System.out.println("✓ 获取到 " + availableTags.size() + " 个标签"); // 步骤2: 模拟前端上传logo.jpg并获取媒体ID System.out.println("\n步骤2: 上传头像图片"); String mediaId = uploadAvatarImage(); assertNotNull(mediaId, "媒体ID不应为空"); System.out.println("✓ 头像上传成功,媒体ID: " + mediaId); // 步骤3: 前端提交评委数据 System.out.println("\n步骤3: 创建评委"); String judgeId = createJudgeWithAvatar(mediaId, availableTags); assertNotNull(judgeId, "评委ID不应为空"); System.out.println("✓ 评委创建成功,ID: " + judgeId); // 步骤4: 验证数据库中的数据完整性 System.out.println("\n步骤4: 验证数据完整性"); verifyJudgeDataIntegrity(judgeId, mediaId); System.out.println("✓ 数据完整性验证通过"); // 步骤5: 前端查询评委详情 System.out.println("\n步骤5: 查询评委详情"); Map judgeDetails = getJudgeDetails(judgeId); assertNotNull(judgeDetails, "评委详情不应为空"); System.out.println("✓ 评委详情查询成功"); System.out.println("\n=== 完整流程测试成功 ==="); printTestSummary(judgeId, mediaId, judgeDetails); } /** * 步骤1: 获取可用标签列表(模拟前端加载标签) */ private List> getAvailableTags() throws Exception { String query = """ query { tagsByCategory(category: "major") { id name code } } """; Map request = Collections.singletonMap("query", query); String response = postGraphQL(request); Map responseMap = objectMapper.readValue(response, Map.class); // 检查是否有错误 if (responseMap.containsKey("errors")) { System.out.println("GraphQL错误: " + responseMap.get("errors")); throw new RuntimeException("GraphQL查询失败: " + responseMap.get("errors")); } Map data = (Map) responseMap.get("data"); if (data == null) { throw new RuntimeException("GraphQL响应中没有data字段"); } @SuppressWarnings("unchecked") List> tags = (List>) data.get("tagsByCategory"); if (tags == null) { // 如果没有专业标签,尝试获取所有标签 String allTagsQuery = """ query { tags { id name code } } """; Map allTagsRequest = Collections.singletonMap("query", allTagsQuery); String allTagsResponse = postGraphQL(allTagsRequest); Map allTagsResponseMap = objectMapper.readValue(allTagsResponse, Map.class); Map allTagsData = (Map) allTagsResponseMap.get("data"); @SuppressWarnings("unchecked") List> allTags = (List>) allTagsData.get("tags"); // 返回前几个标签作为测试数据 return allTags != null ? allTags.stream().limit(2).toList() : Collections.emptyList(); } return tags; } /** * 步骤2: 上传头像图片(模拟前端上传logo.jpg) */ private String uploadAvatarImage() throws Exception { String mutation = """ mutation { saveMedia( name: "logo.jpg" path: "avatars/logo_test.jpg" fileSize: 2048 fileExt: "jpg" mediaType: 1 targetType: 1 targetId: 0 ) { id name path } } """; Map request = Collections.singletonMap("query", mutation); String response = postGraphQL(request); Map responseMap = objectMapper.readValue(response, Map.class); @SuppressWarnings("unchecked") Map mediaData = (Map) ((Map) responseMap.get("data")).get("saveMedia"); Object idObj = mediaData.get("id"); return idObj != null ? idObj.toString() : null; } /** * 步骤3: 创建评委(模拟前端提交表单) */ private String createJudgeWithAvatar(String mediaId, List> availableTags) throws Exception { // 选择前两个专业标签 List selectedTagIds = availableTags.stream() .limit(2) .map(tag -> tag.get("id").toString()) .toList(); String tagIdsStr = "[" + String.join(", ", selectedTagIds) + "]"; String mutation = String.format(""" mutation { saveJudge(input: { name: "李四" phone: "13700137000" gender: 0 description: "资深技术专家,拥有丰富的项目经验和团队管理能力。" specialtyIds: %s avatarMediaId: %s }) { id name phone gender description avatarUrl specialties { id name code } } } """, tagIdsStr, mediaId); Map request = Collections.singletonMap("query", mutation); String response = postGraphQL(request); Map responseMap = objectMapper.readValue(response, Map.class); @SuppressWarnings("unchecked") Map judgeData = (Map) ((Map) responseMap.get("data")).get("saveJudge"); Object idObj = judgeData.get("id"); return idObj != null ? idObj.toString() : null; } /** * 步骤4: 验证数据库数据完整性 */ private void verifyJudgeDataIntegrity(String judgeId, String mediaId) { // 验证评委基本信息 String judgeSql = "SELECT * FROM t_judge WHERE id = ? AND state = 1"; Map judge = jdbcTemplate.queryForMap(judgeSql, Long.parseLong(judgeId)); assertEquals("李四", judge.get("name")); assertEquals("13700137000", judge.get("phone")); assertEquals(0, judge.get("gender")); // 女性 assertTrue(((String) judge.get("description")).contains("资深技术专家")); // 验证媒体记录 String mediaSql = "SELECT * FROM t_media WHERE id = ? AND state = 1"; Map media = jdbcTemplate.queryForMap(mediaSql, Long.parseLong(mediaId)); assertEquals("logo.jpg", media.get("name")); assertEquals(1, media.get("target_type")); // 评委头像 assertEquals(Long.parseLong(judgeId), ((Number) media.get("target_id")).longValue()); // 验证标签关联 String tagSql = "SELECT COUNT(*) FROM t_judge_tag WHERE judge_id = ? AND state = 1"; Integer tagCount = jdbcTemplate.queryForObject(tagSql, Integer.class, Long.parseLong(judgeId)); assertTrue(tagCount >= 2, "应该至少有2个标签关联"); System.out.println(" ✓ 评委基本信息正确"); System.out.println(" ✓ 头像媒体记录正确"); System.out.println(" ✓ 标签关联记录正确 (" + tagCount + "个)"); } /** * 步骤5: 查询评委详情(模拟前端查看详情) */ private Map getJudgeDetails(String judgeId) throws Exception { String query = String.format(""" query { judge(id: %s) { id name phone gender description avatarUrl specialties { id name code } } } """, judgeId); Map request = Collections.singletonMap("query", query); String response = postGraphQL(request); Map responseMap = objectMapper.readValue(response, Map.class); @SuppressWarnings("unchecked") Map judgeData = (Map) ((Map) responseMap.get("data")).get("judge"); return judgeData; } /** * 打印测试总结 */ private void printTestSummary(String judgeId, String mediaId, Map judgeDetails) { System.out.println("\n=== 测试总结 ==="); System.out.println("评委ID: " + judgeId); System.out.println("媒体ID: " + mediaId); System.out.println("评委姓名: " + judgeDetails.get("name")); System.out.println("联系电话: " + judgeDetails.get("phone")); System.out.println("性别: " + (Integer.valueOf(0).equals(judgeDetails.get("gender")) ? "女" : "男")); System.out.println("头像URL: " + judgeDetails.get("avatarUrl")); @SuppressWarnings("unchecked") List> specialties = (List>) judgeDetails.get("specialties"); System.out.println("专业标签数量: " + (specialties != null ? specialties.size() : 0)); if (specialties != null) { for (Map specialty : specialties) { System.out.println(" - " + specialty.get("name") + " (" + specialty.get("category") + ")"); } } System.out.println("\n✅ 所有测试步骤均成功完成!"); System.out.println("✅ 前端到后端的完整数据流程验证通过!"); System.out.println("✅ 数据库数据完整性验证通过!"); } /** * 发送GraphQL请求 */ private String postGraphQL(Map requestBody) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity> entity = new HttpEntity<>(requestBody, headers); String url = "http://localhost:" + port + "/graphql"; var response = restTemplate.postForEntity(url, entity, String.class); if (response.getStatusCode().is2xxSuccessful() && response.hasBody()) { return response.getBody(); } else { throw new RuntimeException("GraphQL request failed with status: " + response.getStatusCode() + " and body: " + response.getBody()); } } }