houzhongyi
2024-07-11 e7c1260db32209a078a962aaa0ad5492c35774fb
提交 | 用户 | 时间
e7c126 1 package com.iailab.module.system.service.social;
H 2
3 import cn.binarywang.wx.miniapp.api.WxMaService;
4 import cn.binarywang.wx.miniapp.api.WxMaUserService;
5 import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
6 import cn.hutool.core.util.ReflectUtil;
7 import com.iailab.framework.common.enums.CommonStatusEnum;
8 import com.iailab.framework.common.enums.UserTypeEnum;
9 import com.iailab.framework.common.pojo.PageResult;
10 import com.iailab.framework.test.core.ut.BaseDbUnitTest;
11 import com.iailab.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
12 import com.iailab.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
13 import com.iailab.module.system.dal.dataobject.social.SocialClientDO;
14 import com.iailab.module.system.dal.mysql.social.SocialClientMapper;
15 import com.iailab.module.system.enums.social.SocialTypeEnum;
16 import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
17 import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
18 import com.xingyuv.jushauth.config.AuthConfig;
19 import com.xingyuv.jushauth.model.AuthResponse;
20 import com.xingyuv.jushauth.model.AuthUser;
21 import com.xingyuv.jushauth.request.AuthDefaultRequest;
22 import com.xingyuv.jushauth.request.AuthRequest;
23 import com.xingyuv.jushauth.utils.AuthStateUtils;
24 import com.xingyuv.justauth.AuthRequestFactory;
25 import me.chanjar.weixin.common.bean.WxJsapiSignature;
26 import me.chanjar.weixin.common.error.WxErrorException;
27 import me.chanjar.weixin.mp.api.WxMpService;
28 import org.junit.jupiter.api.Test;
29 import org.mockito.MockedStatic;
30 import org.springframework.boot.test.mock.mockito.MockBean;
31 import org.springframework.context.annotation.Import;
32 import org.springframework.data.redis.core.StringRedisTemplate;
33
34 import javax.annotation.Resource;
35
36 import static cn.hutool.core.util.RandomUtil.randomEle;
37 import static com.iailab.framework.common.util.object.ObjectUtils.cloneIgnoreId;
38 import static com.iailab.framework.test.core.util.AssertUtils.assertPojoEquals;
39 import static com.iailab.framework.test.core.util.AssertUtils.assertServiceException;
40 import static com.iailab.framework.test.core.util.RandomUtils.*;
41 import static com.iailab.module.system.enums.ErrorCodeConstants.*;
42 import static org.junit.jupiter.api.Assertions.*;
43 import static org.mockito.Mockito.*;
44
45 /**
46  * {@link SocialClientServiceImpl} 的单元测试类
47  *
48  * @author iailab
49  */
50 @Import(SocialClientServiceImpl.class)
51 public class SocialClientServiceImplTest extends BaseDbUnitTest {
52
53     @Resource
54     private SocialClientServiceImpl socialClientService;
55
56     @Resource
57     private SocialClientMapper socialClientMapper;
58
59     @MockBean
60     private AuthRequestFactory authRequestFactory;
61
62     @MockBean
63     private WxMpService wxMpService;
64     @MockBean
65     private WxMpProperties wxMpProperties;
66     @MockBean
67     private StringRedisTemplate stringRedisTemplate;
68     @MockBean
69     private WxMaService wxMaService;
70     @MockBean
71     private WxMaProperties wxMaProperties;
72
73     @Test
74     public void testGetAuthorizeUrl() {
75         try (MockedStatic<AuthStateUtils> authStateUtilsMock = mockStatic(AuthStateUtils.class)) {
76             // 准备参数
77             Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
78             Integer userType = randomPojo(UserTypeEnum.class).getValue();
79             String redirectUri = "sss";
80             // mock 获得对应的 AuthRequest 实现
81             AuthRequest authRequest = mock(AuthRequest.class);
82             when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
83             // mock 方法
84             authStateUtilsMock.when(AuthStateUtils::createState).thenReturn("aoteman");
85             when(authRequest.authorize(eq("aoteman"))).thenReturn("https://www.baidu.com?redirect_uri=yyy");
86
87             // 调用
88             String url = socialClientService.getAuthorizeUrl(socialType, userType, redirectUri);
89             // 断言
90             assertEquals("https://www.baidu.com?redirect_uri=sss", url);
91         }
92     }
93
94     @Test
95     public void testAuthSocialUser_success() {
96         // 准备参数
97         Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
98         Integer userType = randomPojo(UserTypeEnum.class).getValue();
99         String code = randomString();
100         String state = randomString();
101         // mock 方法(AuthRequest)
102         AuthRequest authRequest = mock(AuthRequest.class);
103         when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
104         // mock 方法(AuthResponse)
105         AuthUser authUser = randomPojo(AuthUser.class);
106         AuthResponse<?> authResponse = new AuthResponse<>(2000, null, authUser);
107         when(authRequest.login(argThat(authCallback -> {
108             assertEquals(code, authCallback.getCode());
109             assertEquals(state, authCallback.getState());
110             return true;
111         }))).thenReturn(authResponse);
112
113         // 调用
114         AuthUser result = socialClientService.getAuthUser(socialType, userType, code, state);
115         // 断言
116         assertSame(authUser, result);
117     }
118
119     @Test
120     public void testAuthSocialUser_fail() {
121         // 准备参数
122         Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
123         Integer userType = randomPojo(UserTypeEnum.class).getValue();
124         String code = randomString();
125         String state = randomString();
126         // mock 方法(AuthRequest)
127         AuthRequest authRequest = mock(AuthRequest.class);
128         when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
129         // mock 方法(AuthResponse)
130         AuthResponse<?> authResponse = new AuthResponse<>(0, "模拟失败", null);
131         when(authRequest.login(argThat(authCallback -> {
132             assertEquals(code, authCallback.getCode());
133             assertEquals(state, authCallback.getState());
134             return true;
135         }))).thenReturn(authResponse);
136
137         // 调用并断言
138         assertServiceException(
139                 () -> socialClientService.getAuthUser(socialType, userType, code, state),
140                 SOCIAL_USER_AUTH_FAILURE, "模拟失败");
141     }
142
143     @Test
144     public void testBuildAuthRequest_clientNull() {
145         // 准备参数
146         Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
147         Integer userType = randomPojo(SocialTypeEnum.class).getType();
148         // mock 获得对应的 AuthRequest 实现
149         AuthRequest authRequest = mock(AuthDefaultRequest.class);
150         AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(authRequest, "config");
151         when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
152
153         // 调用
154         AuthRequest result = socialClientService.buildAuthRequest(socialType, userType);
155         // 断言
156         assertSame(authRequest, result);
157         assertSame(authConfig, ReflectUtil.getFieldValue(authConfig, "config"));
158     }
159
160     @Test
161     public void testBuildAuthRequest_clientDisable() {
162         // 准备参数
163         Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
164         Integer userType = randomPojo(SocialTypeEnum.class).getType();
165         // mock 获得对应的 AuthRequest 实现
166         AuthRequest authRequest = mock(AuthDefaultRequest.class);
167         AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(authRequest, "config");
168         when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
169         // mock 数据
170         SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())
171                 .setUserType(userType).setSocialType(socialType));
172         socialClientMapper.insert(client);
173
174         // 调用
175         AuthRequest result = socialClientService.buildAuthRequest(socialType, userType);
176         // 断言
177         assertSame(authRequest, result);
178         assertSame(authConfig, ReflectUtil.getFieldValue(authConfig, "config"));
179     }
180
181     @Test
182     public void testBuildAuthRequest_clientEnable() {
183         // 准备参数
184         Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
185         Integer userType = randomPojo(SocialTypeEnum.class).getType();
186         // mock 获得对应的 AuthRequest 实现
187         AuthConfig authConfig = mock(AuthConfig.class);
188         AuthRequest authRequest = mock(AuthDefaultRequest.class);
189         ReflectUtil.setFieldValue(authRequest, "config", authConfig);
190         when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
191         // mock 数据
192         SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
193                 .setUserType(userType).setSocialType(socialType));
194         socialClientMapper.insert(client);
195
196         // 调用
197         AuthRequest result = socialClientService.buildAuthRequest(socialType, userType);
198         // 断言
199         assertSame(authRequest, result);
200         assertNotSame(authConfig, ReflectUtil.getFieldValue(authRequest, "config"));
201     }
202
203     // =================== 微信公众号独有 ===================
204
205     @Test
206     public void testCreateWxMpJsapiSignature() throws WxErrorException {
207         // 准备参数
208         Integer userType = randomPojo(UserTypeEnum.class).getValue();
209         String url = randomString();
210         // mock 方法
211         WxJsapiSignature signature = randomPojo(WxJsapiSignature.class);
212         when(wxMpService.createJsapiSignature(eq(url))).thenReturn(signature);
213
214         // 调用
215         WxJsapiSignature result = socialClientService.createWxMpJsapiSignature(userType, url);
216         // 断言
217         assertSame(signature, result);
218     }
219
220     @Test
221     public void testGetWxMpService_clientNull() {
222         // 准备参数
223         Integer userType = randomPojo(UserTypeEnum.class).getValue();
224         // mock 方法
225
226         // 调用
227         WxMpService result = socialClientService.getWxMpService(userType);
228         // 断言
229         assertSame(wxMpService, result);
230     }
231
232     @Test
233     public void testGetWxMpService_clientDisable() {
234         // 准备参数
235         Integer userType = randomPojo(UserTypeEnum.class).getValue();
236         // mock 数据
237         SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())
238                 .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MP.getType()));
239         socialClientMapper.insert(client);
240
241         // 调用
242         WxMpService result = socialClientService.getWxMpService(userType);
243         // 断言
244         assertSame(wxMpService, result);
245     }
246
247     @Test
248     public void testGetWxMpService_clientEnable() {
249         // 准备参数
250         Integer userType = randomPojo(UserTypeEnum.class).getValue();
251         // mock 数据
252         SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
253                 .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MP.getType()));
254         socialClientMapper.insert(client);
255         // mock 方法
256         WxMpProperties.ConfigStorage configStorage = mock(WxMpProperties.ConfigStorage.class);
257         when(wxMpProperties.getConfigStorage()).thenReturn(configStorage);
258
259         // 调用
260         WxMpService result = socialClientService.getWxMpService(userType);
261         // 断言
262         assertNotSame(wxMpService, result);
263         assertEquals(client.getClientId(), result.getWxMpConfigStorage().getAppId());
264         assertEquals(client.getClientSecret(), result.getWxMpConfigStorage().getSecret());
265     }
266
267     // =================== 微信小程序独有 ===================
268
269     @Test
270     public void testGetWxMaPhoneNumberInfo_success() throws WxErrorException {
271         // 准备参数
272         Integer userType = randomPojo(UserTypeEnum.class).getValue();
273         String phoneCode = randomString();
274         // mock 方法
275         WxMaUserService userService = mock(WxMaUserService.class);
276         when(wxMaService.getUserService()).thenReturn(userService);
277         WxMaPhoneNumberInfo phoneNumber = randomPojo(WxMaPhoneNumberInfo.class);
278         when(userService.getPhoneNoInfo(eq(phoneCode))).thenReturn(phoneNumber);
279
280         // 调用
281         WxMaPhoneNumberInfo result = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode);
282         // 断言
283         assertSame(phoneNumber, result);
284     }
285
286     @Test
287     public void testGetWxMaPhoneNumberInfo_exception() throws WxErrorException {
288         // 准备参数
289         Integer userType = randomPojo(UserTypeEnum.class).getValue();
290         String phoneCode = randomString();
291         // mock 方法
292         WxMaUserService userService = mock(WxMaUserService.class);
293         when(wxMaService.getUserService()).thenReturn(userService);
294         WxErrorException wxErrorException = randomPojo(WxErrorException.class);
295         when(userService.getPhoneNoInfo(eq(phoneCode))).thenThrow(wxErrorException);
296
297         // 调用并断言异常
298         assertServiceException(() -> socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode),
299                 SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR);
300     }
301
302     @Test
303     public void testGetWxMaService_clientNull() {
304         // 准备参数
305         Integer userType = randomPojo(UserTypeEnum.class).getValue();
306         // mock 方法
307
308         // 调用
309         WxMaService result = socialClientService.getWxMaService(userType);
310         // 断言
311         assertSame(wxMaService, result);
312     }
313
314     @Test
315     public void testGetWxMaService_clientDisable() {
316         // 准备参数
317         Integer userType = randomPojo(UserTypeEnum.class).getValue();
318         // mock 数据
319         SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())
320                 .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType()));
321         socialClientMapper.insert(client);
322
323         // 调用
324         WxMaService result = socialClientService.getWxMaService(userType);
325         // 断言
326         assertSame(wxMaService, result);
327     }
328
329     @Test
330     public void testGetWxMaService_clientEnable() {
331         // 准备参数
332         Integer userType = randomPojo(UserTypeEnum.class).getValue();
333         // mock 数据
334         SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
335                 .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType()));
336         socialClientMapper.insert(client);
337         // mock 方法
338         WxMaProperties.ConfigStorage configStorage = mock(WxMaProperties.ConfigStorage.class);
339         when(wxMaProperties.getConfigStorage()).thenReturn(configStorage);
340
341         // 调用
342         WxMaService result = socialClientService.getWxMaService(userType);
343         // 断言
344         assertNotSame(wxMaService, result);
345         assertEquals(client.getClientId(), result.getWxMaConfig().getAppid());
346         assertEquals(client.getClientSecret(), result.getWxMaConfig().getSecret());
347     }
348
349     // =================== 客户端管理 ===================
350
351     @Test
352     public void testCreateSocialClient_success() {
353         // 准备参数
354         SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class,
355                 o -> o.setSocialType(randomEle(SocialTypeEnum.values()).getType())
356                         .setUserType(randomEle(UserTypeEnum.values()).getValue())
357                         .setStatus(randomCommonStatus()))
358                 .setId(null); // 防止 id 被赋值
359
360         // 调用
361         Long socialClientId = socialClientService.createSocialClient(reqVO);
362         // 断言
363         assertNotNull(socialClientId);
364         // 校验记录的属性是否正确
365         SocialClientDO socialClient = socialClientMapper.selectById(socialClientId);
366         assertPojoEquals(reqVO, socialClient, "id");
367     }
368
369     @Test
370     public void testUpdateSocialClient_success() {
371         // mock 数据
372         SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class);
373         socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据
374         // 准备参数
375         SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class, o -> {
376             o.setId(dbSocialClient.getId()); // 设置更新的 ID
377             o.setSocialType(randomEle(SocialTypeEnum.values()).getType())
378                     .setUserType(randomEle(UserTypeEnum.values()).getValue())
379                     .setStatus(randomCommonStatus());
380         });
381
382         // 调用
383         socialClientService.updateSocialClient(reqVO);
384         // 校验是否更新正确
385         SocialClientDO socialClient = socialClientMapper.selectById(reqVO.getId()); // 获取最新的
386         assertPojoEquals(reqVO, socialClient);
387     }
388
389     @Test
390     public void testUpdateSocialClient_notExists() {
391         // 准备参数
392         SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class);
393
394         // 调用, 并断言异常
395         assertServiceException(() -> socialClientService.updateSocialClient(reqVO), SOCIAL_CLIENT_NOT_EXISTS);
396     }
397
398     @Test
399     public void testDeleteSocialClient_success() {
400         // mock 数据
401         SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class);
402         socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据
403         // 准备参数
404         Long id = dbSocialClient.getId();
405
406         // 调用
407         socialClientService.deleteSocialClient(id);
408         // 校验数据不存在了
409         assertNull(socialClientMapper.selectById(id));
410     }
411
412     @Test
413     public void testDeleteSocialClient_notExists() {
414         // 准备参数
415         Long id = randomLongId();
416
417         // 调用, 并断言异常
418         assertServiceException(() -> socialClientService.deleteSocialClient(id), SOCIAL_CLIENT_NOT_EXISTS);
419     }
420
421     @Test
422     public void testGetSocialClient() {
423         // mock 数据
424         SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class);
425         socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据
426         // 准备参数
427         Long id = dbSocialClient.getId();
428
429         // 调用
430         SocialClientDO socialClient = socialClientService.getSocialClient(id);
431         // 校验数据正确
432         assertPojoEquals(dbSocialClient, socialClient);
433     }
434
435     @Test
436     public void testGetSocialClientPage() {
437         // mock 数据
438         SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class, o -> { // 等会查询到
439             o.setName("芋头");
440             o.setSocialType(SocialTypeEnum.GITEE.getType());
441             o.setUserType(UserTypeEnum.ADMIN.getValue());
442             o.setClientId("iailab");
443             o.setStatus(CommonStatusEnum.ENABLE.getStatus());
444         });
445         socialClientMapper.insert(dbSocialClient);
446         // 测试 name 不匹配
447         socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setName(randomString())));
448         // 测试 socialType 不匹配
449         socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setSocialType(SocialTypeEnum.DINGTALK.getType())));
450         // 测试 userType 不匹配
451         socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
452         // 测试 clientId 不匹配
453         socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientId("dao")));
454         // 测试 status 不匹配
455         socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
456         // 准备参数
457         SocialClientPageReqVO reqVO = new SocialClientPageReqVO();
458         reqVO.setName("芋");
459         reqVO.setSocialType(SocialTypeEnum.GITEE.getType());
460         reqVO.setUserType(UserTypeEnum.ADMIN.getValue());
461         reqVO.setClientId("yu");
462         reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
463
464         // 调用
465         PageResult<SocialClientDO> pageResult = socialClientService.getSocialClientPage(reqVO);
466         // 断言
467         assertEquals(1, pageResult.getTotal());
468         assertEquals(1, pageResult.getList().size());
469         assertPojoEquals(dbSocialClient, pageResult.getList().get(0));
470     }
471
472 }