Selaa lähdekoodia

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

YunaiV 1 vuosi sitten
vanhempi
commit
c2e9ecf7be

+ 1 - 1
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 {
     @Schema(description = "用户昵称", example = "李四")
     private String nickname;
 
-    @Schema(description = "社交 openid", example = "oz-Jdt0kd_jdhUxJHQdBJMlOFN7w\n")
+    @Schema(description = "社交 openid", example = "oz-Jdt0kd_jdhUxJHQdBJMlOFN7w")
     private String openid;
 
     @Schema(description = "创建时间")

+ 7 - 5
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 {
      * @param userType 用户类型
      * @return AuthRequest 对象
      */
-    private AuthRequest buildAuthRequest(Integer socialType, Integer userType) {
+    @VisibleForTesting
+    AuthRequest buildAuthRequest(Integer socialType, Integer userType) {
         // 1. 先查找默认的配置项,从 application-*.yaml 中读取
         AuthRequest request = authRequestFactory.get(SocialTypeEnum.valueOfType(socialType).getSource());
         Assert.notNull(request, String.format("社交平台(%d) 不存在", socialType));
@@ -180,7 +181,8 @@ public class SocialClientServiceImpl implements SocialClientService {
      * @param userType 用户类型
      * @return WxMpService 对象
      */
-    private WxMpService getWxMpService(Integer userType) {
+    @VisibleForTesting
+    WxMpService getWxMpService(Integer userType) {
         // 第一步,查询 DB 的配置项,获得对应的 WxMpService 对象
         SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
                 SocialTypeEnum.WECHAT_MP.getType(), userType);
@@ -198,7 +200,7 @@ public class SocialClientServiceImpl implements SocialClientService {
      * @param clientSecret 微信公众号 secret
      * @return WxMpService 对象
      */
-    private WxMpService buildWxMpService(String clientId, String clientSecret) {
+    public WxMpService buildWxMpService(String clientId, String clientSecret) {
         // 第一步,创建 WxMpRedisConfigImpl 对象
         WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl(
                 new RedisTemplateWxRedisOps(stringRedisTemplate),
@@ -231,7 +233,8 @@ public class SocialClientServiceImpl implements SocialClientService {
      * @param userType 用户类型
      * @return WxMpService 对象
      */
-    private WxMaService getWxMaService(Integer userType) {
+    @VisibleForTesting
+    WxMaService getWxMaService(Integer userType) {
         // 第一步,查询 DB 的配置项,获得对应的 WxMaService 对象
         SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
                 SocialTypeEnum.WECHAT_MINI_APP.getType(), userType);
@@ -311,7 +314,6 @@ public class SocialClientServiceImpl implements SocialClientService {
      * @param userType 用户类型
      * @param socialType 社交类型
      */
-    @VisibleForTesting
     private void validateSocialClientUnique(Long id, Integer userType, Integer socialType) {
         SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
                 socialType, userType);

+ 3 - 6
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java

@@ -1,14 +1,12 @@
 package cn.iocoder.yudao.module.system.service.social;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.lang.Assert;
 import cn.iocoder.yudao.framework.common.exception.ServiceException;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
-import cn.iocoder.yudao.module.system.convert.social.SocialUserConvert;
 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
@@ -22,14 +20,14 @@ import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
 import javax.validation.constraints.NotNull;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
-import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AUTH_THIRD_LOGIN_NOT_BIND;
+import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND;
 
 /**
  * 社交用户 Service 实现类
@@ -61,7 +59,7 @@ public class SocialUserServiceImpl implements SocialUserService {
     }
 
     @Override
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     public String bindSocialUser(SocialUserBindReqDTO reqDTO) {
         // 获得社交用户
         SocialUserDO socialUser = authSocialUser(reqDTO.getSocialType(), reqDTO.getUserType(),
@@ -110,7 +108,6 @@ public class SocialUserServiceImpl implements SocialUserService {
         return new SocialUserRespDTO(socialUser.getOpenid(), socialUserBind.getUserId());
     }
 
-    // TODO 芋艿:调整下单测
     /**
      * 授权获得对应的社交用户
      * 如果授权失败,则会抛出 {@link ServiceException} 异常

+ 354 - 29
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImplTest.java

@@ -1,33 +1,53 @@
 package cn.iocoder.yudao.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 cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
-import org.junit.jupiter.api.Disabled;
+import cn.iocoder.yudao.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 cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
-import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
-import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
-import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_CLIENT_NOT_EXISTS;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
 import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
 
-// TODO 芋艿:单测后续补充下;
 /**
  * {@link SocialClientServiceImpl} 的单元测试类
  *
  * @author 芋道源码
  */
 @Import(SocialClientServiceImpl.class)
-@Disabled
 public class SocialClientServiceImplTest extends BaseDbUnitTest {
 
     @Resource
@@ -36,10 +56,305 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
     @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<AuthStateUtils> 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.iocoder.cn?redirect_uri=yyy");
+
+            // 调用
+            String url = socialClientService.getAuthorizeUrl(socialType, userType, redirectUri);
+            // 断言
+            assertEquals("https://www.iocoder.cn?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)
+        SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class,
+                o -> o.setSocialType(randomEle(SocialTypeEnum.values()).getType())
+                        .setUserType(randomEle(UserTypeEnum.values()).getValue())
+                        .setStatus(randomCommonStatus()))
                 .setId(null); // 防止 id 被赋值
 
         // 调用
@@ -59,6 +374,9 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
         // 准备参数
         SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class, o -> {
             o.setId(dbSocialClient.getId()); // 设置更新的 ID
+            o.setSocialType(randomEle(SocialTypeEnum.values()).getType())
+                    .setUserType(randomEle(UserTypeEnum.values()).getValue())
+                    .setStatus(randomCommonStatus());
         });
 
         // 调用
@@ -101,40 +419,47 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
     }
 
     @Test
-    @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+    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(null);
-            o.setSocialType(null);
-            o.setUserType(null);
-            o.setClientId(null);
-            o.setClientSecret(null);
-            o.setStatus(null);
-            o.setCreateTime(null);
+            o.setName("芋头");
+            o.setSocialType(SocialTypeEnum.GITEE.getType());
+            o.setUserType(UserTypeEnum.ADMIN.getValue());
+            o.setClientId("yudao");
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus());
         });
         socialClientMapper.insert(dbSocialClient);
         // 测试 name 不匹配
-        socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setName(null)));
+        socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setName(randomString())));
         // 测试 socialType 不匹配
-        socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setSocialType(null)));
+        socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setSocialType(SocialTypeEnum.DINGTALK.getType())));
         // 测试 userType 不匹配
-        socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setUserType(null)));
+        socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
         // 测试 clientId 不匹配
-        socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientId(null)));
-        // 测试 clientSecret 不匹配
-        socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientSecret(null)));
+        socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientId("dao")));
         // 测试 status 不匹配
-        socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(null)));
-        // 测试 createTime 不匹配
-        socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setCreateTime(null)));
+        socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
         // 准备参数
         SocialClientPageReqVO reqVO = new SocialClientPageReqVO();
-        reqVO.setName(null);
-        reqVO.setSocialType(null);
-        reqVO.setUserType(null);
-        reqVO.setClientId(null);
-        reqVO.setStatus(null);
+        reqVO.setName("芋");
+        reqVO.setSocialType(SocialTypeEnum.GITEE.getType());
+        reqVO.setUserType(UserTypeEnum.ADMIN.getValue());
+        reqVO.setClientId("yu");
+        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
 
         // 调用
         PageResult<SocialClientDO> pageResult = socialClientService.getSocialClientPage(reqVO);

+ 148 - 123
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImplTest.java

@@ -1,21 +1,17 @@
 package cn.iocoder.yudao.module.system.service.social;
 
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
+import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper;
 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
-import com.xingyuv.jushauth.enums.AuthResponseStatus;
-import com.xingyuv.jushauth.model.AuthCallback;
-import com.xingyuv.jushauth.model.AuthResponse;
 import com.xingyuv.jushauth.model.AuthUser;
-import com.xingyuv.jushauth.request.AuthRequest;
-import com.xingyuv.justauth.AuthRequestFactory;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.context.annotation.Import;
@@ -23,18 +19,27 @@ import org.springframework.context.annotation.Import;
 import javax.annotation.Resource;
 import java.util.List;
 
-import static cn.hutool.core.util.RandomUtil.*;
+import static cn.hutool.core.util.RandomUtil.randomEle;
+import static cn.hutool.core.util.RandomUtil.randomLong;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
-import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_AUTH_FAILURE;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND;
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.when;
 
+/**
+ * {@link SocialUserServiceImpl} 的单元测试类
+ *
+ * @author 芋道源码
+ */
 @Import(SocialUserServiceImpl.class)
-@Disabled // TODO 芋艿:后续统一修复
 public class SocialUserServiceImplTest extends BaseDbUnitTest {
 
     @Resource
@@ -46,119 +51,7 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
     private SocialUserBindMapper socialUserBindMapper;
 
     @MockBean
-    private AuthRequestFactory authRequestFactory;
-
-    // TODO 芋艿:后续统一修复
-//    @Test
-//    public void testGetAuthorizeUrl() {
-//        try (MockedStatic<AuthStateUtils> authStateUtilsMock = mockStatic(AuthStateUtils.class)) {
-//            // 准备参数
-//            Integer type = SocialTypeEnum.WECHAT_MP.getType();
-//            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.iocoder.cn?redirect_uri=yyy");
-//
-//            // 调用
-//            String url = socialUserService.getAuthorizeUrl(type, redirectUri);
-//            // 断言
-//            assertEquals("https://www.iocoder.cn?redirect_uri=sss", url);
-//        }
-//    }
-
-    @Test
-    public void testAuthSocialUser_exists() {
-        // 准备参数
-        Integer socialType = SocialTypeEnum.GITEE.getType();
-        Integer userType = randomEle(SocialTypeEnum.values()).getType();
-        String code = "tudou";
-        String state = "yuanma";
-        // mock 方法
-        SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(socialType).setCode(code).setState(state);
-        socialUserMapper.insert(socialUser);
-
-        // 调用
-        SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
-        // 断言
-        assertPojoEquals(socialUser, result);
-    }
-
-    @Test
-    public void testAuthSocialUser_authFailure() {
-        // 准备参数
-        Integer socialType = SocialTypeEnum.GITEE.getType();
-        Integer userType = randomEle(SocialTypeEnum.values()).getType();
-        // mock 方法
-        AuthRequest authRequest = mock(AuthRequest.class);
-        when(authRequestFactory.get(anyString())).thenReturn(authRequest);
-        AuthResponse<?> authResponse = new AuthResponse<>(0, "模拟失败", null);
-        when(authRequest.login(any(AuthCallback.class))).thenReturn(authResponse);
-
-        // 调用并断言
-        assertServiceException(
-                () -> socialUserService.authSocialUser(socialType, userType, randomString(10), randomString(10)),
-                SOCIAL_USER_AUTH_FAILURE, "模拟失败");
-    }
-
-    @Test
-    public void testAuthSocialUser_insert() {
-        // 准备参数
-        Integer socialType = SocialTypeEnum.GITEE.getType();
-        Integer userType = randomEle(SocialTypeEnum.values()).getType();
-        String code = "tudou";
-        String state = "yuanma";
-        // mock 方法
-        AuthRequest authRequest = mock(AuthRequest.class);
-        when(authRequestFactory.get(eq(SocialTypeEnum.GITEE.getSource()))).thenReturn(authRequest);
-        AuthUser authUser = randomPojo(AuthUser.class);
-        AuthResponse<AuthUser> authResponse = new AuthResponse<>(AuthResponseStatus.SUCCESS.getCode(), null, authUser);
-        when(authRequest.login(any(AuthCallback.class))).thenReturn(authResponse);
-
-        // 调用
-        SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
-        // 断言
-        assertBindSocialUser(socialType, result, authResponse.getData());
-        assertEquals(code, result.getCode());
-        assertEquals(state, result.getState());
-    }
-
-    @Test
-    public void testAuthSocialUser_update() {
-        // 准备参数
-        Integer socialType = SocialTypeEnum.GITEE.getType();
-        Integer userType = randomEle(SocialTypeEnum.values()).getType();
-        String code = "tudou";
-        String state = "yuanma";
-        // mock 数据
-        socialUserMapper.insert(randomPojo(SocialUserDO.class).setType(socialType).setOpenid("test_openid"));
-        // mock 方法
-        AuthRequest authRequest = mock(AuthRequest.class);
-        when(authRequestFactory.get(eq(SocialTypeEnum.GITEE.getSource()))).thenReturn(authRequest);
-        AuthUser authUser = randomPojo(AuthUser.class);
-        authUser.getToken().setOpenId("test_openid");
-        AuthResponse<AuthUser> authResponse = new AuthResponse<>(AuthResponseStatus.SUCCESS.getCode(), null, authUser);
-        when(authRequest.login(any(AuthCallback.class))).thenReturn(authResponse);
-
-        // 调用
-        SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
-        // 断言
-        assertBindSocialUser(socialType, result, authResponse.getData());
-        assertEquals(code, result.getCode());
-        assertEquals(state, result.getState());
-    }
-
-    private void assertBindSocialUser(Integer type, SocialUserDO socialUser, AuthUser authUser) {
-        assertEquals(authUser.getToken().getAccessToken(), socialUser.getToken());
-        assertEquals(toJsonString(authUser.getToken()), socialUser.getRawTokenInfo());
-        assertEquals(authUser.getNickname(), socialUser.getNickname());
-        assertEquals(authUser.getAvatar(), socialUser.getAvatar());
-        assertEquals(toJsonString(authUser.getRawUserInfo()), socialUser.getRawUserInfo());
-        assertEquals(type, socialUser.getType());
-        assertEquals(authUser.getUuid(), socialUser.getOpenid());
-    }
+    private SocialClientService socialClientService;
 
     @Test
     public void testGetSocialUserList() {
@@ -260,4 +153,136 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
         assertEquals(socialUserDO.getOpenid(), socialUser.getOpenid());
     }
 
+    @Test
+    public void testAuthSocialUser_exists() {
+        // 准备参数
+        Integer socialType = SocialTypeEnum.GITEE.getType();
+        Integer userType = randomEle(SocialTypeEnum.values()).getType();
+        String code = "tudou";
+        String state = "yuanma";
+        // mock 方法
+        SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(socialType).setCode(code).setState(state);
+        socialUserMapper.insert(socialUser);
+
+        // 调用
+        SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
+        // 断言
+        assertPojoEquals(socialUser, result);
+    }
+
+    @Test
+    public void testAuthSocialUser_notNull() {
+        // mock 数据
+        SocialUserDO socialUser = randomPojo(SocialUserDO.class,
+                o -> o.setType(SocialTypeEnum.GITEE.getType()).setCode("tudou").setState("yuanma"));
+        socialUserMapper.insert(socialUser);
+        // 准备参数
+        Integer socialType = SocialTypeEnum.GITEE.getType();
+        Integer userType = randomEle(SocialTypeEnum.values()).getType();
+        String code = "tudou";
+        String state = "yuanma";
+
+        // 调用
+        SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
+        // 断言
+        assertPojoEquals(socialUser, result);
+    }
+
+    @Test
+    public void testAuthSocialUser_insert() {
+        // 准备参数
+        Integer socialType = SocialTypeEnum.GITEE.getType();
+        Integer userType = randomEle(SocialTypeEnum.values()).getType();
+        String code = "tudou";
+        String state = "yuanma";
+        // mock 方法
+        AuthUser authUser = randomPojo(AuthUser.class);
+        when(socialClientService.getAuthUser(eq(socialType), eq(userType), eq(code), eq(state))).thenReturn(authUser);
+
+        // 调用
+        SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
+        // 断言
+        assertBindSocialUser(socialType, result, authUser);
+        assertEquals(code, result.getCode());
+        assertEquals(state, result.getState());
+    }
+
+    @Test
+    public void testAuthSocialUser_update() {
+        // 准备参数
+        Integer socialType = SocialTypeEnum.GITEE.getType();
+        Integer userType = randomEle(SocialTypeEnum.values()).getType();
+        String code = "tudou";
+        String state = "yuanma";
+        // mock 数据
+        socialUserMapper.insert(randomPojo(SocialUserDO.class).setType(socialType).setOpenid("test_openid"));
+        // mock 方法
+        AuthUser authUser = randomPojo(AuthUser.class);
+        when(socialClientService.getAuthUser(eq(socialType), eq(userType), eq(code), eq(state))).thenReturn(authUser);
+
+        // 调用
+        SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
+        // 断言
+        assertBindSocialUser(socialType, result, authUser);
+        assertEquals(code, result.getCode());
+        assertEquals(state, result.getState());
+    }
+
+    private void assertBindSocialUser(Integer type, SocialUserDO socialUser, AuthUser authUser) {
+        assertEquals(authUser.getToken().getAccessToken(), socialUser.getToken());
+        assertEquals(toJsonString(authUser.getToken()), socialUser.getRawTokenInfo());
+        assertEquals(authUser.getNickname(), socialUser.getNickname());
+        assertEquals(authUser.getAvatar(), socialUser.getAvatar());
+        assertEquals(toJsonString(authUser.getRawUserInfo()), socialUser.getRawUserInfo());
+        assertEquals(type, socialUser.getType());
+        assertEquals(authUser.getUuid(), socialUser.getOpenid());
+    }
+
+    @Test
+    public void testGetSocialUser_id() {
+        // mock 数据
+        SocialUserDO socialUserDO = randomPojo(SocialUserDO.class);
+        socialUserMapper.insert(socialUserDO);
+        // 参数准备
+        Long id = socialUserDO.getId();
+
+        // 调用
+        SocialUserDO dbSocialUserDO = socialUserService.getSocialUser(id);
+        // 断言
+        assertPojoEquals(socialUserDO, dbSocialUserDO);
+    }
+
+    @Test
+    public void testGetSocialUserPage() {
+        // mock 数据
+        SocialUserDO dbSocialUser = randomPojo(SocialUserDO.class, o -> { // 等会查询到
+            o.setType(SocialTypeEnum.GITEE.getType());
+            o.setNickname("芋艿");
+            o.setOpenid("yudaoyuanma");
+            o.setCreateTime(buildTime(2020, 1, 15));
+        });
+        socialUserMapper.insert(dbSocialUser);
+        // 测试 type 不匹配
+        socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setType(SocialTypeEnum.DINGTALK.getType())));
+        // 测试 nickname 不匹配
+        socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setNickname(randomString())));
+        // 测试 openid 不匹配
+        socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setOpenid("java")));
+        // 测试 createTime 不匹配
+        socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setCreateTime(buildTime(2020, 1, 21))));
+        // 准备参数
+        SocialUserPageReqVO reqVO = new SocialUserPageReqVO();
+        reqVO.setType(SocialTypeEnum.GITEE.getType());
+        reqVO.setNickname("芋");
+        reqVO.setOpenid("yudao");
+        reqVO.setCreateTime(buildBetweenTime(2020, 1, 10, 2020, 1, 20));
+
+        // 调用
+        PageResult<SocialUserDO> pageResult = socialUserService.getSocialUserPage(reqVO);
+        // 断言
+        assertEquals(1, pageResult.getTotal());
+        assertEquals(1, pageResult.getList().size());
+        assertPojoEquals(dbSocialUser, pageResult.getList().get(0));
+    }
+
 }

+ 2 - 1
yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql

@@ -361,13 +361,14 @@ CREATE TABLE IF NOT EXISTS "system_social_client" (
   "user_type" int NOT NULL,
   "client_id" varchar(255) NOT NULL,
   "client_secret" varchar(255) NOT NULL,
+  "agent_id" varchar(255) NOT NULL,
   "status" int NOT NULL,
   "creator" varchar(64) DEFAULT '',
   "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
   "updater" varchar(64) DEFAULT '',
   "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
   "deleted" bit NOT NULL DEFAULT FALSE,
-  "tenant_id" bigint NOT NULL,
+  "tenant_id" bigint not null default  '0',
   PRIMARY KEY ("id")
 ) COMMENT '社交客户端表';