package com.iailab.module.system.service.social; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.WxMaUserService; import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; import cn.hutool.core.util.ReflectUtil; import com.iailab.framework.common.enums.CommonStatusEnum; import com.iailab.framework.common.enums.UserTypeEnum; import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.test.core.ut.BaseDbUnitTest; import com.iailab.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO; import com.iailab.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; import com.iailab.module.system.dal.dataobject.social.SocialClientDO; import com.iailab.module.system.dal.mysql.social.SocialClientMapper; import com.iailab.module.system.enums.social.SocialTypeEnum; import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties; import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; import com.xingyuv.jushauth.config.AuthConfig; import com.xingyuv.jushauth.model.AuthResponse; import com.xingyuv.jushauth.model.AuthUser; import com.xingyuv.jushauth.request.AuthDefaultRequest; import com.xingyuv.jushauth.request.AuthRequest; import com.xingyuv.jushauth.utils.AuthStateUtils; import com.xingyuv.justauth.AuthRequestFactory; import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import org.springframework.data.redis.core.StringRedisTemplate; import javax.annotation.Resource; import static cn.hutool.core.util.RandomUtil.randomEle; import static com.iailab.framework.common.util.object.ObjectUtils.cloneIgnoreId; import static com.iailab.framework.test.core.util.AssertUtils.assertPojoEquals; import static com.iailab.framework.test.core.util.AssertUtils.assertServiceException; import static com.iailab.framework.test.core.util.RandomUtils.*; import static com.iailab.module.system.enums.ErrorCodeConstants.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; /** * {@link SocialClientServiceImpl} 的单元测试类 * * @author iailab */ @Import(SocialClientServiceImpl.class) public class SocialClientServiceImplTest extends BaseDbUnitTest { @Resource private SocialClientServiceImpl socialClientService; @Resource private SocialClientMapper socialClientMapper; @MockBean private AuthRequestFactory authRequestFactory; @MockBean private WxMpService wxMpService; @MockBean private WxMpProperties wxMpProperties; @MockBean private StringRedisTemplate stringRedisTemplate; @MockBean private WxMaService wxMaService; @MockBean private WxMaProperties wxMaProperties; @Test public void testGetAuthorizeUrl() { try (MockedStatic authStateUtilsMock = mockStatic(AuthStateUtils.class)) { // 准备参数 Integer socialType = SocialTypeEnum.WECHAT_MP.getType(); Integer userType = randomPojo(UserTypeEnum.class).getValue(); String redirectUri = "sss"; // mock 获得对应的 AuthRequest 实现 AuthRequest authRequest = mock(AuthRequest.class); when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest); // mock 方法 authStateUtilsMock.when(AuthStateUtils::createState).thenReturn("aoteman"); when(authRequest.authorize(eq("aoteman"))).thenReturn("https://www.baidu.com?redirect_uri=yyy"); // 调用 String url = socialClientService.getAuthorizeUrl(socialType, userType, redirectUri); // 断言 assertEquals("https://www.baidu.com?redirect_uri=sss", url); } } @Test public void testAuthSocialUser_success() { // 准备参数 Integer socialType = SocialTypeEnum.WECHAT_MP.getType(); Integer userType = randomPojo(UserTypeEnum.class).getValue(); String code = randomString(); String state = randomString(); // mock 方法(AuthRequest) AuthRequest authRequest = mock(AuthRequest.class); when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest); // mock 方法(AuthResponse) AuthUser authUser = randomPojo(AuthUser.class); AuthResponse authResponse = new AuthResponse<>(2000, null, authUser); when(authRequest.login(argThat(authCallback -> { assertEquals(code, authCallback.getCode()); assertEquals(state, authCallback.getState()); return true; }))).thenReturn(authResponse); // 调用 AuthUser result = socialClientService.getAuthUser(socialType, userType, code, state); // 断言 assertSame(authUser, result); } @Test public void testAuthSocialUser_fail() { // 准备参数 Integer socialType = SocialTypeEnum.WECHAT_MP.getType(); Integer userType = randomPojo(UserTypeEnum.class).getValue(); String code = randomString(); String state = randomString(); // mock 方法(AuthRequest) AuthRequest authRequest = mock(AuthRequest.class); when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest); // mock 方法(AuthResponse) AuthResponse authResponse = new AuthResponse<>(0, "模拟失败", null); when(authRequest.login(argThat(authCallback -> { assertEquals(code, authCallback.getCode()); assertEquals(state, authCallback.getState()); return true; }))).thenReturn(authResponse); // 调用并断言 assertServiceException( () -> socialClientService.getAuthUser(socialType, userType, code, state), SOCIAL_USER_AUTH_FAILURE, "模拟失败"); } @Test public void testBuildAuthRequest_clientNull() { // 准备参数 Integer socialType = SocialTypeEnum.WECHAT_MP.getType(); Integer userType = randomPojo(SocialTypeEnum.class).getType(); // mock 获得对应的 AuthRequest 实现 AuthRequest authRequest = mock(AuthDefaultRequest.class); AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(authRequest, "config"); when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest); // 调用 AuthRequest result = socialClientService.buildAuthRequest(socialType, userType); // 断言 assertSame(authRequest, result); assertSame(authConfig, ReflectUtil.getFieldValue(authConfig, "config")); } @Test public void testBuildAuthRequest_clientDisable() { // 准备参数 Integer socialType = SocialTypeEnum.WECHAT_MP.getType(); Integer userType = randomPojo(SocialTypeEnum.class).getType(); // mock 获得对应的 AuthRequest 实现 AuthRequest authRequest = mock(AuthDefaultRequest.class); AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(authRequest, "config"); when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest); // mock 数据 SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()) .setUserType(userType).setSocialType(socialType)); socialClientMapper.insert(client); // 调用 AuthRequest result = socialClientService.buildAuthRequest(socialType, userType); // 断言 assertSame(authRequest, result); assertSame(authConfig, ReflectUtil.getFieldValue(authConfig, "config")); } @Test public void testBuildAuthRequest_clientEnable() { // 准备参数 Integer socialType = SocialTypeEnum.WECHAT_MP.getType(); Integer userType = randomPojo(SocialTypeEnum.class).getType(); // mock 获得对应的 AuthRequest 实现 AuthConfig authConfig = mock(AuthConfig.class); AuthRequest authRequest = mock(AuthDefaultRequest.class); ReflectUtil.setFieldValue(authRequest, "config", authConfig); when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest); // mock 数据 SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()) .setUserType(userType).setSocialType(socialType)); socialClientMapper.insert(client); // 调用 AuthRequest result = socialClientService.buildAuthRequest(socialType, userType); // 断言 assertSame(authRequest, result); assertNotSame(authConfig, ReflectUtil.getFieldValue(authRequest, "config")); } // =================== 微信公众号独有 =================== @Test public void testCreateWxMpJsapiSignature() throws WxErrorException { // 准备参数 Integer userType = randomPojo(UserTypeEnum.class).getValue(); String url = randomString(); // mock 方法 WxJsapiSignature signature = randomPojo(WxJsapiSignature.class); when(wxMpService.createJsapiSignature(eq(url))).thenReturn(signature); // 调用 WxJsapiSignature result = socialClientService.createWxMpJsapiSignature(userType, url); // 断言 assertSame(signature, result); } @Test public void testGetWxMpService_clientNull() { // 准备参数 Integer userType = randomPojo(UserTypeEnum.class).getValue(); // mock 方法 // 调用 WxMpService result = socialClientService.getWxMpService(userType); // 断言 assertSame(wxMpService, result); } @Test public void testGetWxMpService_clientDisable() { // 准备参数 Integer userType = randomPojo(UserTypeEnum.class).getValue(); // mock 数据 SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()) .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MP.getType())); socialClientMapper.insert(client); // 调用 WxMpService result = socialClientService.getWxMpService(userType); // 断言 assertSame(wxMpService, result); } @Test public void testGetWxMpService_clientEnable() { // 准备参数 Integer userType = randomPojo(UserTypeEnum.class).getValue(); // mock 数据 SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()) .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MP.getType())); socialClientMapper.insert(client); // mock 方法 WxMpProperties.ConfigStorage configStorage = mock(WxMpProperties.ConfigStorage.class); when(wxMpProperties.getConfigStorage()).thenReturn(configStorage); // 调用 WxMpService result = socialClientService.getWxMpService(userType); // 断言 assertNotSame(wxMpService, result); assertEquals(client.getClientId(), result.getWxMpConfigStorage().getAppId()); assertEquals(client.getClientSecret(), result.getWxMpConfigStorage().getSecret()); } // =================== 微信小程序独有 =================== @Test public void testGetWxMaPhoneNumberInfo_success() throws WxErrorException { // 准备参数 Integer userType = randomPojo(UserTypeEnum.class).getValue(); String phoneCode = randomString(); // mock 方法 WxMaUserService userService = mock(WxMaUserService.class); when(wxMaService.getUserService()).thenReturn(userService); WxMaPhoneNumberInfo phoneNumber = randomPojo(WxMaPhoneNumberInfo.class); when(userService.getPhoneNoInfo(eq(phoneCode))).thenReturn(phoneNumber); // 调用 WxMaPhoneNumberInfo result = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode); // 断言 assertSame(phoneNumber, result); } @Test public void testGetWxMaPhoneNumberInfo_exception() throws WxErrorException { // 准备参数 Integer userType = randomPojo(UserTypeEnum.class).getValue(); String phoneCode = randomString(); // mock 方法 WxMaUserService userService = mock(WxMaUserService.class); when(wxMaService.getUserService()).thenReturn(userService); WxErrorException wxErrorException = randomPojo(WxErrorException.class); when(userService.getPhoneNoInfo(eq(phoneCode))).thenThrow(wxErrorException); // 调用并断言异常 assertServiceException(() -> socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode), SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR); } @Test public void testGetWxMaService_clientNull() { // 准备参数 Integer userType = randomPojo(UserTypeEnum.class).getValue(); // mock 方法 // 调用 WxMaService result = socialClientService.getWxMaService(userType); // 断言 assertSame(wxMaService, result); } @Test public void testGetWxMaService_clientDisable() { // 准备参数 Integer userType = randomPojo(UserTypeEnum.class).getValue(); // mock 数据 SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()) .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())); socialClientMapper.insert(client); // 调用 WxMaService result = socialClientService.getWxMaService(userType); // 断言 assertSame(wxMaService, result); } @Test public void testGetWxMaService_clientEnable() { // 准备参数 Integer userType = randomPojo(UserTypeEnum.class).getValue(); // mock 数据 SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()) .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType())); socialClientMapper.insert(client); // mock 方法 WxMaProperties.ConfigStorage configStorage = mock(WxMaProperties.ConfigStorage.class); when(wxMaProperties.getConfigStorage()).thenReturn(configStorage); // 调用 WxMaService result = socialClientService.getWxMaService(userType); // 断言 assertNotSame(wxMaService, result); assertEquals(client.getClientId(), result.getWxMaConfig().getAppid()); assertEquals(client.getClientSecret(), result.getWxMaConfig().getSecret()); } // =================== 客户端管理 =================== @Test public void testCreateSocialClient_success() { // 准备参数 SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class, o -> o.setSocialType(randomEle(SocialTypeEnum.values()).getType()) .setUserType(randomEle(UserTypeEnum.values()).getValue()) .setStatus(randomCommonStatus())) .setId(null); // 防止 id 被赋值 // 调用 Long socialClientId = socialClientService.createSocialClient(reqVO); // 断言 assertNotNull(socialClientId); // 校验记录的属性是否正确 SocialClientDO socialClient = socialClientMapper.selectById(socialClientId); assertPojoEquals(reqVO, socialClient, "id"); } @Test public void testUpdateSocialClient_success() { // mock 数据 SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class); socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据 // 准备参数 SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class, o -> { o.setId(dbSocialClient.getId()); // 设置更新的 ID o.setSocialType(randomEle(SocialTypeEnum.values()).getType()) .setUserType(randomEle(UserTypeEnum.values()).getValue()) .setStatus(randomCommonStatus()); }); // 调用 socialClientService.updateSocialClient(reqVO); // 校验是否更新正确 SocialClientDO socialClient = socialClientMapper.selectById(reqVO.getId()); // 获取最新的 assertPojoEquals(reqVO, socialClient); } @Test public void testUpdateSocialClient_notExists() { // 准备参数 SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class); // 调用, 并断言异常 assertServiceException(() -> socialClientService.updateSocialClient(reqVO), SOCIAL_CLIENT_NOT_EXISTS); } @Test public void testDeleteSocialClient_success() { // mock 数据 SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class); socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据 // 准备参数 Long id = dbSocialClient.getId(); // 调用 socialClientService.deleteSocialClient(id); // 校验数据不存在了 assertNull(socialClientMapper.selectById(id)); } @Test public void testDeleteSocialClient_notExists() { // 准备参数 Long id = randomLongId(); // 调用, 并断言异常 assertServiceException(() -> socialClientService.deleteSocialClient(id), SOCIAL_CLIENT_NOT_EXISTS); } @Test public void testGetSocialClient() { // mock 数据 SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class); socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据 // 准备参数 Long id = dbSocialClient.getId(); // 调用 SocialClientDO socialClient = socialClientService.getSocialClient(id); // 校验数据正确 assertPojoEquals(dbSocialClient, socialClient); } @Test public void testGetSocialClientPage() { // mock 数据 SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class, o -> { // 等会查询到 o.setName("芋头"); o.setSocialType(SocialTypeEnum.GITEE.getType()); o.setUserType(UserTypeEnum.ADMIN.getValue()); o.setClientId("iailab"); o.setStatus(CommonStatusEnum.ENABLE.getStatus()); }); socialClientMapper.insert(dbSocialClient); // 测试 name 不匹配 socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setName(randomString()))); // 测试 socialType 不匹配 socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setSocialType(SocialTypeEnum.DINGTALK.getType()))); // 测试 userType 不匹配 socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setUserType(UserTypeEnum.MEMBER.getValue()))); // 测试 clientId 不匹配 socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientId("dao"))); // 测试 status 不匹配 socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); // 准备参数 SocialClientPageReqVO reqVO = new SocialClientPageReqVO(); reqVO.setName("芋"); reqVO.setSocialType(SocialTypeEnum.GITEE.getType()); reqVO.setUserType(UserTypeEnum.ADMIN.getValue()); reqVO.setClientId("yu"); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 调用 PageResult pageResult = socialClientService.getSocialClientPage(reqVO); // 断言 assertEquals(1, pageResult.getTotal()); assertEquals(1, pageResult.getList().size()); assertPojoEquals(dbSocialClient, pageResult.getList().get(0)); } }