Commit c2e9ecf7be47d207464183a5f26e7d81efa5bf5b

Authored by YunaiV
1 parent f6568889

✅ 增加 social 模块的单测覆盖率

yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserPageReqVO.java
... ... @@ -23,7 +23,7 @@ public class SocialUserPageReqVO extends PageParam {
23 23 @Schema(description = "用户昵称", example = "李四")
24 24 private String nickname;
25 25  
26   - @Schema(description = "社交 openid", example = "oz-Jdt0kd_jdhUxJHQdBJMlOFN7w\n")
  26 + @Schema(description = "社交 openid", example = "oz-Jdt0kd_jdhUxJHQdBJMlOFN7w")
27 27 private String openid;
28 28  
29 29 @Schema(description = "创建时间")
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java
... ... @@ -142,7 +142,8 @@ public class SocialClientServiceImpl implements SocialClientService {
142 142 * @param userType 用户类型
143 143 * @return AuthRequest 对象
144 144 */
145   - private AuthRequest buildAuthRequest(Integer socialType, Integer userType) {
  145 + @VisibleForTesting
  146 + AuthRequest buildAuthRequest(Integer socialType, Integer userType) {
146 147 // 1. 先查找默认的配置项,从 application-*.yaml 中读取
147 148 AuthRequest request = authRequestFactory.get(SocialTypeEnum.valueOfType(socialType).getSource());
148 149 Assert.notNull(request, String.format("社交平台(%d) 不存在", socialType));
... ... @@ -180,7 +181,8 @@ public class SocialClientServiceImpl implements SocialClientService {
180 181 * @param userType 用户类型
181 182 * @return WxMpService 对象
182 183 */
183   - private WxMpService getWxMpService(Integer userType) {
  184 + @VisibleForTesting
  185 + WxMpService getWxMpService(Integer userType) {
184 186 // 第一步,查询 DB 的配置项,获得对应的 WxMpService 对象
185 187 SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
186 188 SocialTypeEnum.WECHAT_MP.getType(), userType);
... ... @@ -198,7 +200,7 @@ public class SocialClientServiceImpl implements SocialClientService {
198 200 * @param clientSecret 微信公众号 secret
199 201 * @return WxMpService 对象
200 202 */
201   - private WxMpService buildWxMpService(String clientId, String clientSecret) {
  203 + public WxMpService buildWxMpService(String clientId, String clientSecret) {
202 204 // 第一步,创建 WxMpRedisConfigImpl 对象
203 205 WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl(
204 206 new RedisTemplateWxRedisOps(stringRedisTemplate),
... ... @@ -231,7 +233,8 @@ public class SocialClientServiceImpl implements SocialClientService {
231 233 * @param userType 用户类型
232 234 * @return WxMpService 对象
233 235 */
234   - private WxMaService getWxMaService(Integer userType) {
  236 + @VisibleForTesting
  237 + WxMaService getWxMaService(Integer userType) {
235 238 // 第一步,查询 DB 的配置项,获得对应的 WxMaService 对象
236 239 SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
237 240 SocialTypeEnum.WECHAT_MINI_APP.getType(), userType);
... ... @@ -311,7 +314,6 @@ public class SocialClientServiceImpl implements SocialClientService {
311 314 * @param userType 用户类型
312 315 * @param socialType 社交类型
313 316 */
314   - @VisibleForTesting
315 317 private void validateSocialClientUnique(Long id, Integer userType, Integer socialType) {
316 318 SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
317 319 socialType, userType);
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java
1 1 package cn.iocoder.yudao.module.system.service.social;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4   -import cn.hutool.core.collection.ListUtil;
5 4 import cn.hutool.core.lang.Assert;
6 5 import cn.iocoder.yudao.framework.common.exception.ServiceException;
7 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 7 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
9 8 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
10 9 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
11   -import cn.iocoder.yudao.module.system.convert.social.SocialUserConvert;
12 10 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
13 11 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
14 12 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
... ... @@ -22,14 +20,14 @@ import org.springframework.validation.annotation.Validated;
22 20  
23 21 import javax.annotation.Resource;
24 22 import javax.validation.constraints.NotNull;
25   -import java.util.Collection;
26 23 import java.util.Collections;
27 24 import java.util.List;
28 25  
29 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
30 27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
31 28 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
32   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
  29 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AUTH_THIRD_LOGIN_NOT_BIND;
  30 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND;
33 31  
34 32 /**
35 33 * 社交用户 Service 实现类
... ... @@ -61,7 +59,7 @@ public class SocialUserServiceImpl implements SocialUserService {
61 59 }
62 60  
63 61 @Override
64   - @Transactional
  62 + @Transactional(rollbackFor = Exception.class)
65 63 public String bindSocialUser(SocialUserBindReqDTO reqDTO) {
66 64 // 获得社交用户
67 65 SocialUserDO socialUser = authSocialUser(reqDTO.getSocialType(), reqDTO.getUserType(),
... ... @@ -110,7 +108,6 @@ public class SocialUserServiceImpl implements SocialUserService {
110 108 return new SocialUserRespDTO(socialUser.getOpenid(), socialUserBind.getUserId());
111 109 }
112 110  
113   - // TODO 芋艿:调整下单测
114 111 /**
115 112 * 授权获得对应的社交用户
116 113 * 如果授权失败,则会抛出 {@link ServiceException} 异常
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImplTest.java
1 1 package cn.iocoder.yudao.module.system.service.social;
2 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 cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  8 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
3 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 10 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5 11 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
6 12 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
7 13 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
8 14 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
9   -import org.junit.jupiter.api.Disabled;
  15 +import cn.iocoder.yudao.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;
10 28 import org.junit.jupiter.api.Test;
  29 +import org.mockito.MockedStatic;
  30 +import org.springframework.boot.test.mock.mockito.MockBean;
11 31 import org.springframework.context.annotation.Import;
  32 +import org.springframework.data.redis.core.StringRedisTemplate;
12 33  
13 34 import javax.annotation.Resource;
14 35  
  36 +import static cn.hutool.core.util.RandomUtil.randomEle;
15 37 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
16 38 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
17 39 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
18   -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
19   -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
20   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_CLIENT_NOT_EXISTS;
  40 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  41 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
21 42 import static org.junit.jupiter.api.Assertions.*;
  43 +import static org.mockito.Mockito.*;
22 44  
23   -// TODO 芋艿:单测后续补充下;
24 45 /**
25 46 * {@link SocialClientServiceImpl} 的单元测试类
26 47 *
27 48 * @author 芋道源码
28 49 */
29 50 @Import(SocialClientServiceImpl.class)
30   -@Disabled
31 51 public class SocialClientServiceImplTest extends BaseDbUnitTest {
32 52  
33 53 @Resource
... ... @@ -36,10 +56,305 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
36 56 @Resource
37 57 private SocialClientMapper socialClientMapper;
38 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.iocoder.cn?redirect_uri=yyy");
  86 +
  87 + // 调用
  88 + String url = socialClientService.getAuthorizeUrl(socialType, userType, redirectUri);
  89 + // 断言
  90 + assertEquals("https://www.iocoder.cn?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 +
39 351 @Test
40 352 public void testCreateSocialClient_success() {
41 353 // 准备参数
42   - SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class)
  354 + SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class,
  355 + o -> o.setSocialType(randomEle(SocialTypeEnum.values()).getType())
  356 + .setUserType(randomEle(UserTypeEnum.values()).getValue())
  357 + .setStatus(randomCommonStatus()))
43 358 .setId(null); // 防止 id 被赋值
44 359  
45 360 // 调用
... ... @@ -59,6 +374,9 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
59 374 // 准备参数
60 375 SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class, o -> {
61 376 o.setId(dbSocialClient.getId()); // 设置更新的 ID
  377 + o.setSocialType(randomEle(SocialTypeEnum.values()).getType())
  378 + .setUserType(randomEle(UserTypeEnum.values()).getValue())
  379 + .setStatus(randomCommonStatus());
62 380 });
63 381  
64 382 // 调用
... ... @@ -101,40 +419,47 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
101 419 }
102 420  
103 421 @Test
104   - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  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
105 436 public void testGetSocialClientPage() {
106 437 // mock 数据
107 438 SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class, o -> { // 等会查询到
108   - o.setName(null);
109   - o.setSocialType(null);
110   - o.setUserType(null);
111   - o.setClientId(null);
112   - o.setClientSecret(null);
113   - o.setStatus(null);
114   - o.setCreateTime(null);
  439 + o.setName("芋头");
  440 + o.setSocialType(SocialTypeEnum.GITEE.getType());
  441 + o.setUserType(UserTypeEnum.ADMIN.getValue());
  442 + o.setClientId("yudao");
  443 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
115 444 });
116 445 socialClientMapper.insert(dbSocialClient);
117 446 // 测试 name 不匹配
118   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setName(null)));
  447 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setName(randomString())));
119 448 // 测试 socialType 不匹配
120   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setSocialType(null)));
  449 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setSocialType(SocialTypeEnum.DINGTALK.getType())));
121 450 // 测试 userType 不匹配
122   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setUserType(null)));
  451 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
123 452 // 测试 clientId 不匹配
124   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientId(null)));
125   - // 测试 clientSecret 不匹配
126   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientSecret(null)));
  453 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientId("dao")));
127 454 // 测试 status 不匹配
128   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(null)));
129   - // 测试 createTime 不匹配
130   - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setCreateTime(null)));
  455 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
131 456 // 准备参数
132 457 SocialClientPageReqVO reqVO = new SocialClientPageReqVO();
133   - reqVO.setName(null);
134   - reqVO.setSocialType(null);
135   - reqVO.setUserType(null);
136   - reqVO.setClientId(null);
137   - reqVO.setStatus(null);
  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());
138 463  
139 464 // 调用
140 465 PageResult<SocialClientDO> pageResult = socialClientService.getSocialClientPage(reqVO);
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImplTest.java
1 1 package cn.iocoder.yudao.module.system.service.social;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5 6 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
6 7 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
  8 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
7 9 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
8 10 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
9 11 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
10 12 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper;
11 13 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
12   -import com.xingyuv.jushauth.enums.AuthResponseStatus;
13   -import com.xingyuv.jushauth.model.AuthCallback;
14   -import com.xingyuv.jushauth.model.AuthResponse;
15 14 import com.xingyuv.jushauth.model.AuthUser;
16   -import com.xingyuv.jushauth.request.AuthRequest;
17   -import com.xingyuv.justauth.AuthRequestFactory;
18   -import org.junit.jupiter.api.Disabled;
19 15 import org.junit.jupiter.api.Test;
20 16 import org.springframework.boot.test.mock.mockito.MockBean;
21 17 import org.springframework.context.annotation.Import;
... ... @@ -23,18 +19,27 @@ import org.springframework.context.annotation.Import;
23 19 import javax.annotation.Resource;
24 20 import java.util.List;
25 21  
26   -import static cn.hutool.core.util.RandomUtil.*;
  22 +import static cn.hutool.core.util.RandomUtil.randomEle;
  23 +import static cn.hutool.core.util.RandomUtil.randomLong;
  24 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
  25 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
27 26 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
  27 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
28 28 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
29 29 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
30 30 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
31   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_AUTH_FAILURE;
  31 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
32 32 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND;
33 33 import static org.junit.jupiter.api.Assertions.assertEquals;
34   -import static org.mockito.Mockito.*;
  34 +import static org.mockito.Mockito.eq;
  35 +import static org.mockito.Mockito.when;
35 36  
  37 +/**
  38 + * {@link SocialUserServiceImpl} 的单元测试类
  39 + *
  40 + * @author 芋道源码
  41 + */
36 42 @Import(SocialUserServiceImpl.class)
37   -@Disabled // TODO 芋艿:后续统一修复
38 43 public class SocialUserServiceImplTest extends BaseDbUnitTest {
39 44  
40 45 @Resource
... ... @@ -46,119 +51,7 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
46 51 private SocialUserBindMapper socialUserBindMapper;
47 52  
48 53 @MockBean
49   - private AuthRequestFactory authRequestFactory;
50   -
51   - // TODO 芋艿:后续统一修复
52   -// @Test
53   -// public void testGetAuthorizeUrl() {
54   -// try (MockedStatic<AuthStateUtils> authStateUtilsMock = mockStatic(AuthStateUtils.class)) {
55   -// // 准备参数
56   -// Integer type = SocialTypeEnum.WECHAT_MP.getType();
57   -// String redirectUri = "sss";
58   -// // mock 获得对应的 AuthRequest 实现
59   -// AuthRequest authRequest = mock(AuthRequest.class);
60   -// when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
61   -// // mock 方法
62   -// authStateUtilsMock.when(AuthStateUtils::createState).thenReturn("aoteman");
63   -// when(authRequest.authorize(eq("aoteman"))).thenReturn("https://www.iocoder.cn?redirect_uri=yyy");
64   -//
65   -// // 调用
66   -// String url = socialUserService.getAuthorizeUrl(type, redirectUri);
67   -// // 断言
68   -// assertEquals("https://www.iocoder.cn?redirect_uri=sss", url);
69   -// }
70   -// }
71   -
72   - @Test
73   - public void testAuthSocialUser_exists() {
74   - // 准备参数
75   - Integer socialType = SocialTypeEnum.GITEE.getType();
76   - Integer userType = randomEle(SocialTypeEnum.values()).getType();
77   - String code = "tudou";
78   - String state = "yuanma";
79   - // mock 方法
80   - SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(socialType).setCode(code).setState(state);
81   - socialUserMapper.insert(socialUser);
82   -
83   - // 调用
84   - SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
85   - // 断言
86   - assertPojoEquals(socialUser, result);
87   - }
88   -
89   - @Test
90   - public void testAuthSocialUser_authFailure() {
91   - // 准备参数
92   - Integer socialType = SocialTypeEnum.GITEE.getType();
93   - Integer userType = randomEle(SocialTypeEnum.values()).getType();
94   - // mock 方法
95   - AuthRequest authRequest = mock(AuthRequest.class);
96   - when(authRequestFactory.get(anyString())).thenReturn(authRequest);
97   - AuthResponse<?> authResponse = new AuthResponse<>(0, "模拟失败", null);
98   - when(authRequest.login(any(AuthCallback.class))).thenReturn(authResponse);
99   -
100   - // 调用并断言
101   - assertServiceException(
102   - () -> socialUserService.authSocialUser(socialType, userType, randomString(10), randomString(10)),
103   - SOCIAL_USER_AUTH_FAILURE, "模拟失败");
104   - }
105   -
106   - @Test
107   - public void testAuthSocialUser_insert() {
108   - // 准备参数
109   - Integer socialType = SocialTypeEnum.GITEE.getType();
110   - Integer userType = randomEle(SocialTypeEnum.values()).getType();
111   - String code = "tudou";
112   - String state = "yuanma";
113   - // mock 方法
114   - AuthRequest authRequest = mock(AuthRequest.class);
115   - when(authRequestFactory.get(eq(SocialTypeEnum.GITEE.getSource()))).thenReturn(authRequest);
116   - AuthUser authUser = randomPojo(AuthUser.class);
117   - AuthResponse<AuthUser> authResponse = new AuthResponse<>(AuthResponseStatus.SUCCESS.getCode(), null, authUser);
118   - when(authRequest.login(any(AuthCallback.class))).thenReturn(authResponse);
119   -
120   - // 调用
121   - SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
122   - // 断言
123   - assertBindSocialUser(socialType, result, authResponse.getData());
124   - assertEquals(code, result.getCode());
125   - assertEquals(state, result.getState());
126   - }
127   -
128   - @Test
129   - public void testAuthSocialUser_update() {
130   - // 准备参数
131   - Integer socialType = SocialTypeEnum.GITEE.getType();
132   - Integer userType = randomEle(SocialTypeEnum.values()).getType();
133   - String code = "tudou";
134   - String state = "yuanma";
135   - // mock 数据
136   - socialUserMapper.insert(randomPojo(SocialUserDO.class).setType(socialType).setOpenid("test_openid"));
137   - // mock 方法
138   - AuthRequest authRequest = mock(AuthRequest.class);
139   - when(authRequestFactory.get(eq(SocialTypeEnum.GITEE.getSource()))).thenReturn(authRequest);
140   - AuthUser authUser = randomPojo(AuthUser.class);
141   - authUser.getToken().setOpenId("test_openid");
142   - AuthResponse<AuthUser> authResponse = new AuthResponse<>(AuthResponseStatus.SUCCESS.getCode(), null, authUser);
143   - when(authRequest.login(any(AuthCallback.class))).thenReturn(authResponse);
144   -
145   - // 调用
146   - SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
147   - // 断言
148   - assertBindSocialUser(socialType, result, authResponse.getData());
149   - assertEquals(code, result.getCode());
150   - assertEquals(state, result.getState());
151   - }
152   -
153   - private void assertBindSocialUser(Integer type, SocialUserDO socialUser, AuthUser authUser) {
154   - assertEquals(authUser.getToken().getAccessToken(), socialUser.getToken());
155   - assertEquals(toJsonString(authUser.getToken()), socialUser.getRawTokenInfo());
156   - assertEquals(authUser.getNickname(), socialUser.getNickname());
157   - assertEquals(authUser.getAvatar(), socialUser.getAvatar());
158   - assertEquals(toJsonString(authUser.getRawUserInfo()), socialUser.getRawUserInfo());
159   - assertEquals(type, socialUser.getType());
160   - assertEquals(authUser.getUuid(), socialUser.getOpenid());
161   - }
  54 + private SocialClientService socialClientService;
162 55  
163 56 @Test
164 57 public void testGetSocialUserList() {
... ... @@ -260,4 +153,136 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
260 153 assertEquals(socialUserDO.getOpenid(), socialUser.getOpenid());
261 154 }
262 155  
  156 + @Test
  157 + public void testAuthSocialUser_exists() {
  158 + // 准备参数
  159 + Integer socialType = SocialTypeEnum.GITEE.getType();
  160 + Integer userType = randomEle(SocialTypeEnum.values()).getType();
  161 + String code = "tudou";
  162 + String state = "yuanma";
  163 + // mock 方法
  164 + SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(socialType).setCode(code).setState(state);
  165 + socialUserMapper.insert(socialUser);
  166 +
  167 + // 调用
  168 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
  169 + // 断言
  170 + assertPojoEquals(socialUser, result);
  171 + }
  172 +
  173 + @Test
  174 + public void testAuthSocialUser_notNull() {
  175 + // mock 数据
  176 + SocialUserDO socialUser = randomPojo(SocialUserDO.class,
  177 + o -> o.setType(SocialTypeEnum.GITEE.getType()).setCode("tudou").setState("yuanma"));
  178 + socialUserMapper.insert(socialUser);
  179 + // 准备参数
  180 + Integer socialType = SocialTypeEnum.GITEE.getType();
  181 + Integer userType = randomEle(SocialTypeEnum.values()).getType();
  182 + String code = "tudou";
  183 + String state = "yuanma";
  184 +
  185 + // 调用
  186 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
  187 + // 断言
  188 + assertPojoEquals(socialUser, result);
  189 + }
  190 +
  191 + @Test
  192 + public void testAuthSocialUser_insert() {
  193 + // 准备参数
  194 + Integer socialType = SocialTypeEnum.GITEE.getType();
  195 + Integer userType = randomEle(SocialTypeEnum.values()).getType();
  196 + String code = "tudou";
  197 + String state = "yuanma";
  198 + // mock 方法
  199 + AuthUser authUser = randomPojo(AuthUser.class);
  200 + when(socialClientService.getAuthUser(eq(socialType), eq(userType), eq(code), eq(state))).thenReturn(authUser);
  201 +
  202 + // 调用
  203 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
  204 + // 断言
  205 + assertBindSocialUser(socialType, result, authUser);
  206 + assertEquals(code, result.getCode());
  207 + assertEquals(state, result.getState());
  208 + }
  209 +
  210 + @Test
  211 + public void testAuthSocialUser_update() {
  212 + // 准备参数
  213 + Integer socialType = SocialTypeEnum.GITEE.getType();
  214 + Integer userType = randomEle(SocialTypeEnum.values()).getType();
  215 + String code = "tudou";
  216 + String state = "yuanma";
  217 + // mock 数据
  218 + socialUserMapper.insert(randomPojo(SocialUserDO.class).setType(socialType).setOpenid("test_openid"));
  219 + // mock 方法
  220 + AuthUser authUser = randomPojo(AuthUser.class);
  221 + when(socialClientService.getAuthUser(eq(socialType), eq(userType), eq(code), eq(state))).thenReturn(authUser);
  222 +
  223 + // 调用
  224 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
  225 + // 断言
  226 + assertBindSocialUser(socialType, result, authUser);
  227 + assertEquals(code, result.getCode());
  228 + assertEquals(state, result.getState());
  229 + }
  230 +
  231 + private void assertBindSocialUser(Integer type, SocialUserDO socialUser, AuthUser authUser) {
  232 + assertEquals(authUser.getToken().getAccessToken(), socialUser.getToken());
  233 + assertEquals(toJsonString(authUser.getToken()), socialUser.getRawTokenInfo());
  234 + assertEquals(authUser.getNickname(), socialUser.getNickname());
  235 + assertEquals(authUser.getAvatar(), socialUser.getAvatar());
  236 + assertEquals(toJsonString(authUser.getRawUserInfo()), socialUser.getRawUserInfo());
  237 + assertEquals(type, socialUser.getType());
  238 + assertEquals(authUser.getUuid(), socialUser.getOpenid());
  239 + }
  240 +
  241 + @Test
  242 + public void testGetSocialUser_id() {
  243 + // mock 数据
  244 + SocialUserDO socialUserDO = randomPojo(SocialUserDO.class);
  245 + socialUserMapper.insert(socialUserDO);
  246 + // 参数准备
  247 + Long id = socialUserDO.getId();
  248 +
  249 + // 调用
  250 + SocialUserDO dbSocialUserDO = socialUserService.getSocialUser(id);
  251 + // 断言
  252 + assertPojoEquals(socialUserDO, dbSocialUserDO);
  253 + }
  254 +
  255 + @Test
  256 + public void testGetSocialUserPage() {
  257 + // mock 数据
  258 + SocialUserDO dbSocialUser = randomPojo(SocialUserDO.class, o -> { // 等会查询到
  259 + o.setType(SocialTypeEnum.GITEE.getType());
  260 + o.setNickname("芋艿");
  261 + o.setOpenid("yudaoyuanma");
  262 + o.setCreateTime(buildTime(2020, 1, 15));
  263 + });
  264 + socialUserMapper.insert(dbSocialUser);
  265 + // 测试 type 不匹配
  266 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setType(SocialTypeEnum.DINGTALK.getType())));
  267 + // 测试 nickname 不匹配
  268 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setNickname(randomString())));
  269 + // 测试 openid 不匹配
  270 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setOpenid("java")));
  271 + // 测试 createTime 不匹配
  272 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setCreateTime(buildTime(2020, 1, 21))));
  273 + // 准备参数
  274 + SocialUserPageReqVO reqVO = new SocialUserPageReqVO();
  275 + reqVO.setType(SocialTypeEnum.GITEE.getType());
  276 + reqVO.setNickname("芋");
  277 + reqVO.setOpenid("yudao");
  278 + reqVO.setCreateTime(buildBetweenTime(2020, 1, 10, 2020, 1, 20));
  279 +
  280 + // 调用
  281 + PageResult<SocialUserDO> pageResult = socialUserService.getSocialUserPage(reqVO);
  282 + // 断言
  283 + assertEquals(1, pageResult.getTotal());
  284 + assertEquals(1, pageResult.getList().size());
  285 + assertPojoEquals(dbSocialUser, pageResult.getList().get(0));
  286 + }
  287 +
263 288 }
... ...
yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql
... ... @@ -361,13 +361,14 @@ CREATE TABLE IF NOT EXISTS &quot;system_social_client&quot; (
361 361 "user_type" int NOT NULL,
362 362 "client_id" varchar(255) NOT NULL,
363 363 "client_secret" varchar(255) NOT NULL,
  364 + "agent_id" varchar(255) NOT NULL,
364 365 "status" int NOT NULL,
365 366 "creator" varchar(64) DEFAULT '',
366 367 "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
367 368 "updater" varchar(64) DEFAULT '',
368 369 "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
369 370 "deleted" bit NOT NULL DEFAULT FALSE,
370   - "tenant_id" bigint NOT NULL,
  371 + "tenant_id" bigint not null default '0',
371 372 PRIMARY KEY ("id")
372 373 ) COMMENT '社交客户端表';
373 374  
... ...