blob: 9d7c908812b9f3703c4b7e73e4bc06b54f6029d1 [file] [log] [blame]
xiukirad0a7a082025-06-05 16:28:08 +08001package com.g9.g9backend.controller;
2
xiukiradbe96222025-06-06 21:25:09 +08003import com.fasterxml.jackson.databind.ObjectMapper;
4import com.g9.g9backend.pojo.*;
5import com.g9.g9backend.pojo.DTO.*;
6import com.g9.g9backend.service.*;
7import org.junit.jupiter.api.BeforeEach;
8import org.junit.jupiter.api.Test;
9import org.mockito.InjectMocks;
10import org.mockito.Mock;
11import org.mockito.MockitoAnnotations;
12import org.springframework.http.MediaType;
13import org.springframework.test.web.servlet.MockMvc;
14import org.springframework.test.web.servlet.setup.MockMvcBuilders;
15
16import java.util.Date;
17
18import static org.mockito.ArgumentMatchers.*;
19import static org.mockito.Mockito.when;
20import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
21import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
22
23/*
24 @SpringBootTest 启动一个完整的 Spring 应用上下文,用来测试整个应用的行为
25 @AutoConfigureMockMvc 自动配置 MockMvc 对象,MockMvc 是 Spring 提供的工具,用来模拟 HTTP 请求,从而不需要启动真正的服务器来发送HTTP请求就能进行测试
26 注意@SpringBootTest 已经自动配置了 Mockito 或 Spring 的 Mock 环境,再在setup中手动调用 openMocks(this) 可能导致 Mock 对象被重复初始化
27 出现状态丢失问题(如 when().thenReturn() 规则失效),所以改为使用 JUnit 5 默认运行器,不需要在这里写注解
28*/
xiukirad0a7a082025-06-05 16:28:08 +080029public class ResourceControllerTest {
30
xiukiradbe96222025-06-06 21:25:09 +080031 // MockMvc对象
32 private MockMvc mockMvc;
33
34 // @InjectMocks告诉测试框架(Mockito)创建 ResourceController 的实例,并自动将标注了 @Mock 的依赖注入到这个实例中
35 @InjectMocks
36 private ResourceController resourceController;
37
38 // @Mock告诉 Mockito 创建这些依赖的“模拟对象”,用来模拟服务行为,和controller层使用的service依赖一一对应即可
39 @Mock
40 private ResourceService resourceService;
41
42 @Mock
43 private GameplayService gameplayService;
44
45 @Mock
46 private RewardService rewardService;
47
48 @Mock
49 private UserUploadService userUploadService;
50
51 @Mock
52 private CommunityService communityService;
53
54 @Mock
55 private UserService userService;
56
57 @Mock
58 private UserPurchaseService userPurchaseService;
59
60 @Mock
61 private UserLikeService userLikeService;
62
63 @Mock
64 private UserCollectionService userCollectionService;
65
66 @Mock
67 private NotificationService notificationService;
68
69 // ObjectMapper对象用于将 Java 对象和 JSON 字符串互相转换 ,因为在测试中,需要把请求参数或返回响应转换成 JSON 字符串形式来传输
70 private final ObjectMapper objectMapper = new ObjectMapper();
71
72 // 这个方法会在每个测试方法执行之前运行。用来设置测试的初始化逻辑
73 @BeforeEach
74 public void setup() {
75 MockitoAnnotations.openMocks(this);
76 mockMvc = MockMvcBuilders.standaloneSetup(resourceController).build();
77 }
78
79 // 以下是对各接口的测试,注意测试方法是要对每个接口的每个响应测试(如果一个接口有三种响应,就写三个测试方法)
80 // 上传资源
81 @Test
82 public void testUploadResource() throws Exception {
83
84 // 创建测试用的请求数据
85 PostResourceDTO postResourceDTO = new PostResourceDTO();
86 Resource resource = new Resource();
87 resource.setResourceId(1);
88 resource.setResourceName("Test Resource");
89 resource.setUploadTime(new Date());
90 resource.setLastUpdateTime(new Date());
91 resource.setPrice(1);
92 resource.setClassify("map");
93 postResourceDTO.setResource(resource);
94 postResourceDTO.setGameplayList(new String[]{"Gameplay1", "Gameplay2"});
95 postResourceDTO.setUserId(1);
96
97 /*
98 模拟服务层的行为,when(...).thenReturn(...)表示当某个服务方法被调用时,返回一个指定的结果(注意mybatis-plus的这些方法一般返回是boolean类型,所以写true不能写null)
99 同样是测试方法,测试粒度有区别
100 有简单写法:when(gameplayService.save(any())).thenReturn(true);只验证方法是否被调用(间接验证逻辑是否执行到该服务方法),不关心方法调用的次数和传递的参数
101 也有复杂写法:额外用 verify 验证调用次数和 ArgumentCaptor 验证参数是否传递正确和InOrder 来验证方法的调用顺序是否正确...
102 */
103
104 // 测试主是要测试传参是否能正确接收,接口调用过程是否使用过这些方法(所以使用到的方法一般来说应该按顺序写在这,不能缺不能多也不能乱序,但是这里实际因为测试粒度不够细,没有对方法调用过程的验证,所以即是方法缺少或调用过程有问题,也不会报错),返回响应是否发送正确
105 when(resourceService.save(any())).thenReturn(true);
106 when(gameplayService.save(any())).thenReturn(true);
107 when(userUploadService.save(any())).thenReturn(true);
108 when(communityService.save(any())).thenReturn(true);
109 when(rewardService.update(any())).thenReturn(true);
110
111 // 模拟 HTTP 请求
112 mockMvc.perform(post("/resource") // 使用 MockMvc 模拟用户提交 POST 请求到 /resource 接口
113 .contentType(MediaType.APPLICATION_JSON) // 设置请求体是 JSON 格式
114 .content(objectMapper.writeValueAsString(postResourceDTO))) //把请求参数对象:postResourceDTO 转成 JSON 字符串,作为请求体内容发送
115 .andExpect(status().isOk()); // 期望接口返回 HTTP 状态码 200(成功)
116 }
117
118 // 购买资源
119 @Test
120 public void testPurchaseResource_success() throws Exception {
121
122 // 用户积分足够
123 User user = new User();
124 user.setUserId(1);
125 user.setCredits(100);
126 Resource resource = new Resource();
127 resource.setResourceId(1);
128 resource.setPrice(50);
129
130 when(userService.getOne(any())).thenReturn(user);
131 when(resourceService.getOne(any())).thenReturn(resource);
132 when(userService.update(any())).thenReturn(true);
133 when(userPurchaseService.save(any())).thenReturn(true);
134 when(userUploadService.getOne(any())).thenReturn(new UserUpload(2, 1));
135 when(notificationService.save(any())).thenReturn(true);
136
137 mockMvc.perform(post("/resource/purchase")
138 .contentType(MediaType.APPLICATION_JSON)
139 .content(objectMapper.writeValueAsString(new UserResourceDTO(1, 1))))
140 .andExpect(status().isOk());
141 }
142
143 @Test
144 public void testPurchaseResource_purchaseFailed() throws Exception {
145
146 //用户积分不足
147 User user = new User();
148 user.setUserId(1);
149 user.setCredits(10);
150 Resource resource = new Resource();
151 resource.setResourceId(1);
152 resource.setPrice(50);
153
154 when(userService.getOne(any())).thenReturn(user);
155 when(resourceService.getOne(any())).thenReturn(resource);
156
157 mockMvc.perform(post("/resource/purchase")
158 .contentType(MediaType.APPLICATION_JSON)
159 .content(objectMapper.writeValueAsString(new UserResourceDTO(1, 1))))
160 .andExpect(status().is(412));
161 }
162
163 // 点赞资源
164 @Test
165 public void testLikeResource() throws Exception {
166
167 User user = new User();
168 user.setUserId(1);
169 Resource resource = new Resource();
170 resource.setResourceId(1);
171
172 when(userService.getOne(any())).thenReturn(user);
173 when(resourceService.getOne(any())).thenReturn(resource);
174 when(userLikeService.save(any())).thenReturn(true);
175 when(userUploadService.getOne(any())).thenReturn(new UserUpload(2, 1));
176 when(notificationService.save(any())).thenReturn(true);
177
178 mockMvc.perform(post("/resource/like")
179 .contentType(MediaType.APPLICATION_JSON)
180 .content(objectMapper.writeValueAsString(new UserResourceDTO(1, 1))))
181 .andExpect(status().isOk());
182 }
183
184 // 收藏资源
185 @Test
186 public void testCollectResource() throws Exception {
187
188 User user = new User();
189 user.setUserId(1);
190 Resource resource = new Resource();
191 resource.setResourceId(1);
192
193 when(userService.getOne(any())).thenReturn(user);
194 when(resourceService.getOne(any())).thenReturn(resource);
195 when(userCollectionService.save(any())).thenReturn(true);
196 when(userUploadService.getOne(any())).thenReturn(new UserUpload(2, 1));
197 when(notificationService.save(any())).thenReturn(true);
198
199 mockMvc.perform(post("/resource/collection")
200 .contentType(MediaType.APPLICATION_JSON)
201 .content(objectMapper.writeValueAsString(new UserResourceDTO(1, 1))))
202 .andExpect(status().isOk());
203 }
xiukirab9490272025-06-06 21:53:52 +0800204
205 // 删除资源
206 @Test
207 public void testDeleteResource_success() throws Exception {
208
209 // 密码正确
210 when(userService.getOne(any())).thenReturn(new User(1, "hcy", "123", null, 0, 0, null, 0, 0, 0));
211 when(resourceService.removeById(1)).thenReturn(true);
212
213 mockMvc.perform(delete("/resource")
214 .param("resourceId", "1")
215 .param("userId", "1")
216 .param("password", "123"))
217 .andExpect(status().isNoContent());
218 }
219
220 @Test
221 public void testDeleteResource_wrongPassword() throws Exception {
222
223 // 密码错误
224 when(userService.getOne(any())).thenReturn(new User(1, "hcy", "123", null, 0, 0, null, 0, 0, 0));
225
226 mockMvc.perform(delete("/resource")
227 .param("resourceId", "1")
228 .param("userId", "1")
229 .param("password", "wrong"))
230 .andExpect(status().is(408));
231 }
232
233 // 取消点赞
234 @Test
235 public void testLikeDelete() throws Exception {
236
237 when(userLikeService.remove(any())).thenReturn(true);
238
239 mockMvc.perform(delete("/resource/like")
240 .param("userId", "1")
241 .param("resourceId", "1"))
242 .andExpect(status().isNoContent());
243 }
244
245 // 取消收藏
246 @Test
247 public void testCollectionDelete() throws Exception {
248
249 when(userCollectionService.remove(any())).thenReturn(true);
250
251 mockMvc.perform(delete("/resource/collection")
252 .param("userId", "1")
253 .param("resourceId", "1"))
254 .andExpect(status().isNoContent());
255 }
xiukirad0a7a082025-06-05 16:28:08 +0800256}