package cn.iocoder.yudao.module.system.service.social;
|
|
import cn.binarywang.wx.miniapp.api.WxMaOrderShippingService;
|
import cn.binarywang.wx.miniapp.api.WxMaService;
|
import cn.binarywang.wx.miniapp.api.WxMaUserService;
|
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
|
import cn.binarywang.wx.miniapp.bean.shop.request.shipping.WxMaOrderShippingInfoUploadRequest;
|
import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingInfoBaseResponse;
|
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.api.social.dto.SocialWxaOrderUploadShippingInfoReqDTO;
|
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 cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
|
import cn.iocoder.yudao.module.system.framework.justauth.core.AuthRequestFactory;
|
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
|
import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
|
import jakarta.annotation.Resource;
|
import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
import me.chanjar.weixin.common.error.WxError;
|
import me.chanjar.weixin.common.error.WxErrorException;
|
import me.chanjar.weixin.mp.api.WxMpService;
|
import me.zhyd.oauth.config.AuthConfig;
|
import me.zhyd.oauth.model.AuthResponse;
|
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.request.AuthDefaultRequest;
|
import me.zhyd.oauth.request.AuthRequest;
|
import me.zhyd.oauth.utils.AuthStateUtils;
|
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.Test;
|
import org.mockito.MockedStatic;
|
import org.springframework.context.annotation.Import;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
|
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.*;
|
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
import static org.mockito.Mockito.*;
|
|
/**
|
* {@link SocialClientServiceImpl} 的单元测试类
|
*
|
* @author 芋道源码
|
*/
|
@Import(SocialClientServiceImpl.class)
|
public class SocialClientServiceImplTest extends BaseDbUnitTest {
|
|
@Resource
|
private SocialClientServiceImpl socialClientService;
|
|
@Resource
|
private SocialClientMapper socialClientMapper;
|
|
@MockitoBean
|
private AuthRequestFactory authRequestFactory;
|
|
@MockitoBean
|
private WxMpService wxMpService;
|
@MockitoBean
|
private WxMpProperties wxMpProperties;
|
@MockitoBean
|
private StringRedisTemplate stringRedisTemplate;
|
@MockitoBean
|
private WxMaService wxMaService;
|
@MockitoBean
|
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<AuthUser> 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<AuthUser> 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.getPhoneNumber(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 = new WxErrorException(new NullPointerException());
|
when(userService.getPhoneNumber(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_PROGRAM.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_PROGRAM.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("yudao");
|
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<SocialClientDO> pageResult = socialClientService.getSocialClientPage(reqVO);
|
// 断言
|
assertEquals(1, pageResult.getTotal());
|
assertEquals(1, pageResult.getList().size());
|
assertPojoEquals(dbSocialClient, pageResult.getList().get(0));
|
}
|
|
// =================== 微信小程序订单发货 ===================
|
|
@BeforeAll
|
public static void setUpUploadShippingBackoff() {
|
// 测试场景下把退避数组的每一项改为 1ms,避免拖慢用例(数组引用是 final 但元素可改)
|
long[] backoff = (long[]) ReflectUtil.getFieldValue(SocialClientServiceImpl.class,
|
"UPLOAD_SHIPPING_INFO_RETRY_BACKOFF_MILLIS");
|
for (int i = 0; i < backoff.length; i++) {
|
backoff[i] = 1L;
|
}
|
}
|
|
@Test
|
public void testUploadWxaOrderShippingInfo_success() throws WxErrorException {
|
// 准备参数
|
Integer userType = randomPojo(UserTypeEnum.class).getValue();
|
SocialWxaOrderUploadShippingInfoReqDTO reqDTO = randomUploadShippingReqDTO();
|
// mock 方法:首次调用就成功
|
WxMaOrderShippingService shippingService = mockWxMaOrderShippingService();
|
when(shippingService.upload(any(WxMaOrderShippingInfoUploadRequest.class)))
|
.thenReturn(new WxMaOrderShippingInfoBaseResponse());
|
|
// 调用
|
socialClientService.uploadWxaOrderShippingInfo(userType, reqDTO);
|
// 断言:仅调用 1 次,无重试
|
verify(shippingService, times(1)).upload(any(WxMaOrderShippingInfoUploadRequest.class));
|
}
|
|
@Test
|
public void testUploadWxaOrderShippingInfo_retryThenSuccess() throws WxErrorException {
|
// 准备参数
|
Integer userType = randomPojo(UserTypeEnum.class).getValue();
|
SocialWxaOrderUploadShippingInfoReqDTO reqDTO = randomUploadShippingReqDTO();
|
// mock 方法:首次抛 10060001,第二次成功
|
WxMaOrderShippingService shippingService = mockWxMaOrderShippingService();
|
when(shippingService.upload(any(WxMaOrderShippingInfoUploadRequest.class)))
|
.thenThrow(buildWxErrorException(10060001))
|
.thenReturn(new WxMaOrderShippingInfoBaseResponse());
|
|
// 调用
|
socialClientService.uploadWxaOrderShippingInfo(userType, reqDTO);
|
// 断言:上传调用了 2 次,触发了 1 次重试
|
verify(shippingService, times(2)).upload(any(WxMaOrderShippingInfoUploadRequest.class));
|
}
|
|
@Test
|
public void testUploadWxaOrderShippingInfo_retryExhausted() throws WxErrorException {
|
// 准备参数
|
Integer userType = randomPojo(UserTypeEnum.class).getValue();
|
SocialWxaOrderUploadShippingInfoReqDTO reqDTO = randomUploadShippingReqDTO();
|
// mock 方法:始终抛 10060001
|
WxMaOrderShippingService shippingService = mockWxMaOrderShippingService();
|
when(shippingService.upload(any(WxMaOrderShippingInfoUploadRequest.class)))
|
.thenThrow(buildWxErrorException(10060001));
|
|
// 调用并断言:重试用尽抛业务异常
|
assertServiceException(() -> socialClientService.uploadWxaOrderShippingInfo(userType, reqDTO),
|
SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR);
|
// 断言:共 4 次尝试(1 次首发 + 3 次重试)
|
verify(shippingService, times(4)).upload(any(WxMaOrderShippingInfoUploadRequest.class));
|
}
|
|
@Test
|
public void testUploadWxaOrderShippingInfo_otherErrorNoRetry() throws WxErrorException {
|
// 准备参数
|
Integer userType = randomPojo(UserTypeEnum.class).getValue();
|
SocialWxaOrderUploadShippingInfoReqDTO reqDTO = randomUploadShippingReqDTO();
|
// mock 方法:抛非 10060001 错误(如 access_token 失效)
|
WxMaOrderShippingService shippingService = mockWxMaOrderShippingService();
|
when(shippingService.upload(any(WxMaOrderShippingInfoUploadRequest.class)))
|
.thenThrow(buildWxErrorException(40001));
|
|
// 调用并断言:立即抛业务异常,无重试
|
assertServiceException(() -> socialClientService.uploadWxaOrderShippingInfo(userType, reqDTO),
|
SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR);
|
verify(shippingService, times(1)).upload(any(WxMaOrderShippingInfoUploadRequest.class));
|
}
|
|
/** 构造一个发货上传请求 */
|
private SocialWxaOrderUploadShippingInfoReqDTO randomUploadShippingReqDTO() {
|
return randomPojo(SocialWxaOrderUploadShippingInfoReqDTO.class,
|
o -> o.setLogisticsType(SocialWxaOrderUploadShippingInfoReqDTO.LOGISTICS_TYPE_EXPRESS));
|
}
|
|
/** mock 出 wxMaService.getWxMaOrderShippingService() 的返回值并返回该 mock */
|
private WxMaOrderShippingService mockWxMaOrderShippingService() {
|
WxMaOrderShippingService shippingService = mock(WxMaOrderShippingService.class);
|
when(wxMaService.getWxMaOrderShippingService()).thenReturn(shippingService);
|
return shippingService;
|
}
|
|
/** 构造指定 errorCode 的 WxErrorException */
|
private WxErrorException buildWxErrorException(int errorCode) {
|
return new WxErrorException(WxError.builder().errorCode(errorCode).errorMsg("mock error").build());
|
}
|
|
}
|