Commit a432b303e6690164466fc2ae63667dea302b592b

Authored by YunaiV
1 parent 71d2f741

完成 AliyunSmsClient 的单元测试

完成 YunpianSmsClient 的单元测试
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java
@@ -24,6 +24,7 @@ import com.aliyuncs.profile.DefaultProfile; @@ -24,6 +24,7 @@ import com.aliyuncs.profile.DefaultProfile;
24 import com.aliyuncs.profile.IClientProfile; 24 import com.aliyuncs.profile.IClientProfile;
25 import com.fasterxml.jackson.annotation.JsonFormat; 25 import com.fasterxml.jackson.annotation.JsonFormat;
26 import com.fasterxml.jackson.annotation.JsonProperty; 26 import com.fasterxml.jackson.annotation.JsonProperty;
  27 +import com.google.common.annotations.VisibleForTesting;
27 import lombok.Data; 28 import lombok.Data;
28 import lombok.extern.slf4j.Slf4j; 29 import lombok.extern.slf4j.Slf4j;
29 30
@@ -53,7 +54,7 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -53,7 +54,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
53 /** 54 /**
54 * 阿里云客户端 55 * 阿里云客户端
55 */ 56 */
56 - private volatile IAcsClient acsClient; 57 + private volatile IAcsClient client;
57 58
58 public AliyunSmsClient(SmsChannelProperties properties) { 59 public AliyunSmsClient(SmsChannelProperties properties) {
59 super(properties, new AliyunSmsCodeMapping()); 60 super(properties, new AliyunSmsCodeMapping());
@@ -64,7 +65,7 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -64,7 +65,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
64 @Override 65 @Override
65 protected void doInit() { 66 protected void doInit() {
66 IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret()); 67 IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret());
67 - acsClient = new DefaultAcsClient(profile); 68 + client = new DefaultAcsClient(profile);
68 } 69 }
69 70
70 @Override 71 @Override
@@ -81,13 +82,6 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -81,13 +82,6 @@ public class AliyunSmsClient extends AbstractSmsClient {
81 return invoke(request, response -> new SmsSendRespDTO().setSerialNo(response.getBizId())); 82 return invoke(request, response -> new SmsSendRespDTO().setSerialNo(response.getBizId()));
82 } 83 }
83 84
84 - private static String formatResultMsg(ClientException ex) {  
85 - if (StrUtil.isEmpty(ex.getErrorDescription())) {  
86 - return ex.getMessage();  
87 - }  
88 - return ex.getErrMsg() + " => " + ex.getErrorDescription();  
89 - }  
90 -  
91 @Override 85 @Override
92 protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable { 86 protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
93 List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class); 87 List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
@@ -115,7 +109,8 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -115,7 +109,8 @@ public class AliyunSmsClient extends AbstractSmsClient {
115 }); 109 });
116 } 110 }
117 111
118 - private Integer convertSmsTemplateAuditStatus(Integer templateStatus) { 112 + @VisibleForTesting
  113 + Integer convertSmsTemplateAuditStatus(Integer templateStatus) {
119 switch (templateStatus) { 114 switch (templateStatus) {
120 case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); 115 case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
121 case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); 116 case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
@@ -124,10 +119,11 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -124,10 +119,11 @@ public class AliyunSmsClient extends AbstractSmsClient {
124 } 119 }
125 } 120 }
126 121
127 - private <T extends AcsResponse, R> SmsCommonResult<R> invoke(AcsRequest<T> request, Function<T, R> responseConsumer) { 122 + @VisibleForTesting
  123 + <T extends AcsResponse, R> SmsCommonResult<R> invoke(AcsRequest<T> request, Function<T, R> responseConsumer) {
128 try { 124 try {
129 // 执行发送. 由于阿里云 sms 短信没有统一的 Response,但是有统一的 code、message、requestId 属性,所以只好反射 125 // 执行发送. 由于阿里云 sms 短信没有统一的 Response,但是有统一的 code、message、requestId 属性,所以只好反射
130 - T sendResult = acsClient.getAcsResponse(request); 126 + T sendResult = client.getAcsResponse(request);
131 String code = (String) ReflectUtil.getFieldValue(sendResult, "code"); 127 String code = (String) ReflectUtil.getFieldValue(sendResult, "code");
132 String message = (String) ReflectUtil.getFieldValue(sendResult, "message"); 128 String message = (String) ReflectUtil.getFieldValue(sendResult, "message");
133 String requestId = (String) ReflectUtil.getFieldValue(sendResult, "requestId"); 129 String requestId = (String) ReflectUtil.getFieldValue(sendResult, "requestId");
@@ -143,6 +139,13 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -143,6 +139,13 @@ public class AliyunSmsClient extends AbstractSmsClient {
143 } 139 }
144 } 140 }
145 141
  142 + private static String formatResultMsg(ClientException ex) {
  143 + if (StrUtil.isEmpty(ex.getErrorDescription())) {
  144 + return ex.getErrMsg();
  145 + }
  146 + return ex.getErrMsg() + " => " + ex.getErrorDescription();
  147 + }
  148 +
146 /** 149 /**
147 * 短信接收状态 150 * 短信接收状态
148 * 151 *
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java
@@ -15,6 +15,7 @@ import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; @@ -15,6 +15,7 @@ import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
15 import cn.iocoder.dashboard.util.json.JsonUtils; 15 import cn.iocoder.dashboard.util.json.JsonUtils;
16 import com.fasterxml.jackson.annotation.JsonFormat; 16 import com.fasterxml.jackson.annotation.JsonFormat;
17 import com.fasterxml.jackson.annotation.JsonProperty; 17 import com.fasterxml.jackson.annotation.JsonProperty;
  18 +import com.google.common.annotations.VisibleForTesting;
18 import com.yunpian.sdk.YunpianClient; 19 import com.yunpian.sdk.YunpianClient;
19 import com.yunpian.sdk.constant.YunpianConstant; 20 import com.yunpian.sdk.constant.YunpianConstant;
20 import com.yunpian.sdk.model.Result; 21 import com.yunpian.sdk.model.Result;
@@ -113,7 +114,8 @@ public class YunpianSmsClient extends AbstractSmsClient { @@ -113,7 +114,8 @@ public class YunpianSmsClient extends AbstractSmsClient {
113 }); 114 });
114 } 115 }
115 116
116 - private Integer convertSmsTemplateAuditStatus(String checkStatus) { 117 + @VisibleForTesting
  118 + Integer convertSmsTemplateAuditStatus(String checkStatus) {
117 switch (checkStatus) { 119 switch (checkStatus) {
118 case "CHECKING": return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); 120 case "CHECKING": return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
119 case "SUCCESS": return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); 121 case "SUCCESS": return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
@@ -122,7 +124,8 @@ public class YunpianSmsClient extends AbstractSmsClient { @@ -122,7 +124,8 @@ public class YunpianSmsClient extends AbstractSmsClient {
122 } 124 }
123 } 125 }
124 126
125 - private <T, R> SmsCommonResult<R> invoke(Supplier<Result<T>> requestConsumer, Function<T, R> responseConsumer) throws Throwable { 127 + @VisibleForTesting
  128 + <T, R> SmsCommonResult<R> invoke(Supplier<Result<T>> requestConsumer, Function<T, R> responseConsumer) throws Throwable {
126 // 执行请求 129 // 执行请求
127 Result<T> result = requestConsumer.get(); 130 Result<T> result = requestConsumer.get();
128 if (result.getThrowable() != null) { 131 if (result.getThrowable() != null) {
src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java
1 package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; 1 package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun;
2 2
  3 +import cn.hutool.core.util.ReflectUtil;
  4 +import cn.iocoder.dashboard.BaseMockitoUnitTest;
  5 +import cn.iocoder.dashboard.common.core.KeyValue;
  6 +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
  7 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
3 import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; 8 import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
  9 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
  10 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
  11 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
  12 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  13 +import cn.iocoder.dashboard.util.collection.MapUtils;
4 import cn.iocoder.dashboard.util.date.DateUtils; 14 import cn.iocoder.dashboard.util.date.DateUtils;
  15 +import com.aliyuncs.AcsRequest;
  16 +import com.aliyuncs.IAcsClient;
  17 +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest;
  18 +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse;
  19 +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
  20 +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
  21 +import com.aliyuncs.exceptions.ClientException;
  22 +import com.google.common.collect.Lists;
5 import org.junit.jupiter.api.Test; 23 import org.junit.jupiter.api.Test;
  24 +import org.mockito.ArgumentMatcher;
6 import org.mockito.InjectMocks; 25 import org.mockito.InjectMocks;
  26 +import org.mockito.Mock;
7 27
8 import java.util.List; 28 import java.util.List;
  29 +import java.util.function.Function;
9 30
10 -import static org.junit.jupiter.api.Assertions.assertEquals;  
11 -import static org.junit.jupiter.api.Assertions.assertTrue; 31 +import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR;
  32 +import static cn.iocoder.dashboard.util.RandomUtils.*;
  33 +import static cn.iocoder.dashboard.util.json.JsonUtils.toJsonString;
  34 +import static org.junit.jupiter.api.Assertions.*;
  35 +import static org.mockito.ArgumentMatchers.any;
  36 +import static org.mockito.ArgumentMatchers.argThat;
  37 +import static org.mockito.Mockito.when;
12 38
13 /** 39 /**
14 * {@link AliyunSmsClient} 的单元测试 40 * {@link AliyunSmsClient} 的单元测试
  41 + *
  42 + * @author 芋道源码
15 */ 43 */
16 -public class AliyunSmsClientTest { 44 +public class AliyunSmsClientTest extends BaseMockitoUnitTest {
  45 +
  46 + private final SmsChannelProperties properties = new SmsChannelProperties()
  47 + .setApiKey(randomString()) // 随机一个 apiKey,避免构建报错
  48 + .setApiSecret(randomString()) // 随机一个 apiSecret,避免构建报错
  49 + .setSignature("芋道源码");
17 50
18 @InjectMocks 51 @InjectMocks
19 - private final AliyunSmsClient smsClient = new AliyunSmsClient(null); 52 + private final AliyunSmsClient smsClient = new AliyunSmsClient(properties);
  53 +
  54 + @Mock
  55 + private IAcsClient client;
20 56
21 @Test 57 @Test
22 - void doInit() { 58 + public void testDoInit() {
  59 + // 准备参数
  60 + // mock 方法
  61 +
  62 + // 调用
  63 + smsClient.doInit();
  64 + // 断言
  65 + assertNotSame(client, ReflectUtil.getFieldValue(smsClient, "acsClient"));
23 } 66 }
24 67
25 @Test 68 @Test
26 - void doSendSms() { 69 + @SuppressWarnings("unchecked")
  70 + public void testDoSendSms() throws ClientException {
  71 + // 准备参数
  72 + Long sendLogId = randomLongId();
  73 + String mobile = randomString();
  74 + String apiTemplateId = randomString();
  75 + List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
  76 + new KeyValue<>("code", 1234), new KeyValue<>("op", "login"));
  77 + // mock 方法
  78 + SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> o.setCode("OK"));
  79 + when(client.getAcsResponse(argThat((ArgumentMatcher<SendSmsRequest>) acsRequest -> {
  80 + assertEquals(mobile, acsRequest.getPhoneNumbers());
  81 + assertEquals(properties.getSignature(), acsRequest.getSignName());
  82 + assertEquals(apiTemplateId, acsRequest.getTemplateCode());
  83 + assertEquals(toJsonString(MapUtils.convertMap(templateParams)), acsRequest.getTemplateParam());
  84 + assertEquals(sendLogId.toString(), acsRequest.getOutId());
  85 + return true;
  86 + }))).thenReturn(response);
  87 +
  88 + // 调用
  89 + SmsCommonResult<SmsSendRespDTO> result = smsClient.doSendSms(sendLogId, mobile,
  90 + apiTemplateId, templateParams);
  91 + // 断言
  92 + assertEquals(response.getCode(), result.getApiCode());
  93 + assertEquals(response.getMessage(), result.getApiMsg());
  94 + assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
  95 + assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
  96 + assertEquals(response.getRequestId(), result.getApiRequestId());
  97 + // 断言结果
  98 + assertEquals(response.getBizId(), result.getData().getSerialNo());
27 } 99 }
28 100
29 @Test 101 @Test
@@ -57,4 +129,96 @@ public class AliyunSmsClientTest { @@ -57,4 +129,96 @@ public class AliyunSmsClientTest {
57 assertEquals(67890L, statuses.get(0).getLogId()); 129 assertEquals(67890L, statuses.get(0).getLogId());
58 } 130 }
59 131
  132 + @Test
  133 + public void testDoGetSmsTemplate() throws ClientException {
  134 + // 准备参数
  135 + String apiTemplateId = randomString();
  136 + // mock 方法
  137 + QuerySmsTemplateResponse response = randomPojo(QuerySmsTemplateResponse.class, o -> {
  138 + o.setCode("OK");
  139 + o.setTemplateStatus(1); // 设置模板通过
  140 + });
  141 + when(client.getAcsResponse(argThat((ArgumentMatcher<QuerySmsTemplateRequest>) acsRequest -> {
  142 + assertEquals(apiTemplateId, acsRequest.getTemplateCode());
  143 + return true;
  144 + }))).thenReturn(response);
  145 +
  146 + // 调用
  147 + SmsCommonResult<SmsTemplateRespDTO> result = smsClient.doGetSmsTemplate(apiTemplateId);
  148 + // 断言
  149 + assertEquals(response.getCode(), result.getApiCode());
  150 + assertEquals(response.getMessage(), result.getApiMsg());
  151 + assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
  152 + assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
  153 + assertEquals(response.getRequestId(), result.getApiRequestId());
  154 + // 断言结果
  155 + assertEquals(response.getTemplateCode(), result.getData().getId());
  156 + assertEquals(response.getTemplateContent(), result.getData().getContent());
  157 + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());
  158 + assertEquals(response.getReason(), result.getData().getAuditReason());
  159 + }
  160 +
  161 + @Test
  162 + public void testConvertSmsTemplateAuditStatus() {
  163 + assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(),
  164 + smsClient.convertSmsTemplateAuditStatus(0));
  165 + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(),
  166 + smsClient.convertSmsTemplateAuditStatus(1));
  167 + assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(),
  168 + smsClient.convertSmsTemplateAuditStatus(2));
  169 + assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus(3),
  170 + "未知审核状态(3)");
  171 + }
  172 +
  173 + @Test
  174 + @SuppressWarnings("unchecked")
  175 + public void testInvoke_throwable() throws ClientException {
  176 + // 准备参数
  177 + QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
  178 + // mock 方法
  179 + ClientException ex = new ClientException("isv.INVALID_PARAMETERS", "参数不正确", randomString());
  180 + when(client.getAcsResponse(any(AcsRequest.class))).thenThrow(ex);
  181 +
  182 + // 调用,并断言异常
  183 + SmsCommonResult<?> result = smsClient.invoke(request,null);
  184 + // 断言
  185 + assertEquals(ex.getErrCode(), result.getApiCode());
  186 + assertEquals(ex.getErrMsg(), result.getApiMsg());
  187 + assertEquals(SMS_API_PARAM_ERROR.getCode(), result.getCode());
  188 + assertEquals(SMS_API_PARAM_ERROR.getMsg(), result.getMsg());
  189 + assertEquals(ex.getRequestId(), result.getApiRequestId());
  190 + }
  191 +
  192 + @Test
  193 + public void testInvoke_success() throws ClientException {
  194 + // 准备参数
  195 + QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
  196 + Function<QuerySmsTemplateResponse, SmsTemplateRespDTO> responseConsumer = response -> {
  197 + SmsTemplateRespDTO data = new SmsTemplateRespDTO();
  198 + data.setId(response.getTemplateCode()).setContent(response.getTemplateContent());
  199 + data.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(response.getReason());
  200 + return data;
  201 + };
  202 + // mock 方法
  203 + QuerySmsTemplateResponse response = randomPojo(QuerySmsTemplateResponse.class, o -> {
  204 + o.setCode("OK");
  205 + o.setTemplateStatus(1); // 设置模板通过
  206 + });
  207 + when(client.getAcsResponse(any(AcsRequest.class))).thenReturn(response);
  208 +
  209 + // 调用
  210 + SmsCommonResult<SmsTemplateRespDTO> result = smsClient.invoke(request, responseConsumer);
  211 + // 断言
  212 + assertEquals(response.getCode(), result.getApiCode());
  213 + assertEquals(response.getMessage(), result.getApiMsg());
  214 + assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
  215 + assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
  216 + assertEquals(response.getRequestId(), result.getApiRequestId());
  217 + // 断言结果
  218 + assertEquals(response.getTemplateCode(), result.getData().getId());
  219 + assertEquals(response.getTemplateContent(), result.getData().getContent());
  220 + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());
  221 + assertEquals(response.getReason(), result.getData().getAuditReason());
  222 + }
  223 +
60 } 224 }
src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java
1 package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; 1 package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian;
2 2
  3 +import cn.hutool.core.util.ReflectUtil;
  4 +import cn.iocoder.dashboard.BaseMockitoUnitTest;
  5 +import cn.iocoder.dashboard.common.core.KeyValue;
  6 +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
  7 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
3 import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; 8 import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
  9 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
  10 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
  11 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
  12 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
4 import cn.iocoder.dashboard.util.date.DateUtils; 13 import cn.iocoder.dashboard.util.date.DateUtils;
  14 +import com.google.common.collect.Lists;
  15 +import com.yunpian.sdk.YunpianClient;
  16 +import com.yunpian.sdk.api.SmsApi;
  17 +import com.yunpian.sdk.api.TplApi;
  18 +import com.yunpian.sdk.constant.YunpianConstant;
  19 +import com.yunpian.sdk.model.Result;
  20 +import com.yunpian.sdk.model.SmsSingleSend;
  21 +import com.yunpian.sdk.model.Template;
5 import org.junit.jupiter.api.Test; 22 import org.junit.jupiter.api.Test;
6 import org.mockito.InjectMocks; 23 import org.mockito.InjectMocks;
  24 +import org.mockito.Mock;
7 25
  26 +import java.util.HashMap;
8 import java.util.List; 27 import java.util.List;
  28 +import java.util.Map;
  29 +import java.util.function.Function;
  30 +import java.util.function.Supplier;
9 31
  32 +import static cn.iocoder.dashboard.util.RandomUtils.*;
  33 +import static com.yunpian.sdk.constant.Code.OK;
10 import static org.junit.jupiter.api.Assertions.*; 34 import static org.junit.jupiter.api.Assertions.*;
  35 +import static org.mockito.Mockito.*;
11 36
12 /** 37 /**
13 * 对 {@link YunpianSmsClient} 的单元测试 38 * 对 {@link YunpianSmsClient} 的单元测试
  39 + *
  40 + * @author 芋道源码
14 */ 41 */
15 -public class YunpianSmsClientTest { 42 +public class YunpianSmsClientTest extends BaseMockitoUnitTest {
  43 +
  44 + private final SmsChannelProperties properties = new SmsChannelProperties()
  45 + .setApiKey(randomString()); // 随机一个 apiKey,避免构建报错
16 46
17 @InjectMocks 47 @InjectMocks
18 - private final YunpianSmsClient smsClient = new YunpianSmsClient(null); 48 + private final YunpianSmsClient smsClient = new YunpianSmsClient(properties);
  49 +
  50 + @Mock
  51 + private YunpianClient client;
19 52
20 @Test 53 @Test
21 - void doInit() { 54 + public void testDoInit() {
  55 + // 准备参数
  56 + // mock 方法
  57 +
  58 + // 调用
  59 + smsClient.doInit();
  60 + // 断言
  61 + assertNotEquals(client, ReflectUtil.getFieldValue(smsClient, "client"));
  62 + verify(client, times(1)).close();
22 } 63 }
23 64
24 @Test 65 @Test
25 - void doSendSms() { 66 + @SuppressWarnings("unchecked")
  67 + public void testDoSendSms() throws Throwable {
  68 + // 准备参数
  69 + Long sendLogId = randomLongId();
  70 + String mobile = randomString();
  71 + String apiTemplateId = randomString();
  72 + List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
  73 + new KeyValue<>("code", 1234), new KeyValue<>("op", "login"));
  74 + // mock sms 方法
  75 + SmsApi smsApi = mock(SmsApi.class);
  76 + when(client.sms()).thenReturn(smsApi);
  77 + // mock tpl_single_send 方法
  78 + Map<String, String> request = new HashMap<>();
  79 + request.put(YunpianConstant.MOBILE, mobile);
  80 + request.put(YunpianConstant.TPL_ID, apiTemplateId);
  81 + request.put(YunpianConstant.TPL_VALUE, "#code#=1234&#op#=login");
  82 + request.put(YunpianConstant.UID, String.valueOf(sendLogId));
  83 + request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl());
  84 + Result<SmsSingleSend> responseResult = randomPojo(Result.class, SmsSingleSend.class,
  85 + o -> o.setCode(OK)); // API 发送成功的 code
  86 + when(smsApi.tpl_single_send(eq(request))).thenReturn(responseResult);
  87 +
  88 + // 调用
  89 + SmsCommonResult<SmsSendRespDTO> result = smsClient.doSendSms(sendLogId, mobile,
  90 + apiTemplateId, templateParams);
  91 + // 断言
  92 + assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode());
  93 + assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg());
  94 + assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
  95 + assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
  96 + assertNull(result.getApiRequestId());
  97 + // 断言结果
  98 + assertEquals(String.valueOf(responseResult.getData().getSid()), result.getData().getSerialNo());
26 } 99 }
27 100
28 @Test 101 @Test
29 - void testDoParseSmsReceiveStatus() throws Throwable { 102 + public void testDoParseSmsReceiveStatus() throws Throwable {
30 // 准备参数 103 // 准备参数
31 String text = "[{\"sid\":9527,\"uid\":1024,\"user_receive_time\":\"2014-03-17 22:55:21\",\"error_msg\":\"\",\"mobile\":\"15205201314\",\"report_status\":\"SUCCESS\"}]"; 104 String text = "[{\"sid\":9527,\"uid\":1024,\"user_receive_time\":\"2014-03-17 22:55:21\",\"error_msg\":\"\",\"mobile\":\"15205201314\",\"report_status\":\"SUCCESS\"}]";
32 // mock 方法 105 // mock 方法
@@ -47,4 +120,83 @@ public class YunpianSmsClientTest { @@ -47,4 +120,83 @@ public class YunpianSmsClientTest {
47 assertEquals(1024L, statuses.get(0).getLogId()); 120 assertEquals(1024L, statuses.get(0).getLogId());
48 } 121 }
49 122
  123 + @Test
  124 + @SuppressWarnings("unchecked")
  125 + public void testDoGetSmsTemplate() throws Throwable {
  126 + // 准备参数
  127 + String apiTemplateId = randomString();
  128 + // mock tpl 方法
  129 + TplApi tplApi = mock(TplApi.class);
  130 + when(client.tpl()).thenReturn(tplApi);
  131 + // mock get 方法
  132 + Map<String, String> request = new HashMap<>();
  133 + request.put(YunpianConstant.APIKEY, properties.getApiKey());
  134 + request.put(YunpianConstant.TPL_ID, apiTemplateId);
  135 + Result<List<Template>> responseResult = randomPojo(Result.class, List.class, o -> {
  136 + o.setCode(OK); // API 发送成功的 code
  137 + o.setData(randomPojoList(Template.class, t -> t.setCheck_status("SUCCESS")));
  138 + });
  139 + when(tplApi.get(eq(request))).thenReturn(responseResult);
  140 +
  141 + // 调用
  142 + SmsCommonResult<SmsTemplateRespDTO> result = smsClient.doGetSmsTemplate(apiTemplateId);
  143 + // 断言
  144 + assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode());
  145 + assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg());
  146 + assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
  147 + assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
  148 + assertNull(result.getApiRequestId());
  149 + // 断言结果
  150 + Template template = responseResult.getData().get(0);
  151 + assertEquals(template.getTpl_id().toString(), result.getData().getId());
  152 + assertEquals(template.getTpl_content(), result.getData().getContent());
  153 + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());
  154 + assertEquals(template.getReason(), result.getData().getAuditReason());
  155 + }
  156 +
  157 + @Test
  158 + public void testConvertSmsTemplateAuditStatus() {
  159 + assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(),
  160 + smsClient.convertSmsTemplateAuditStatus("CHECKING"));
  161 + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(),
  162 + smsClient.convertSmsTemplateAuditStatus("SUCCESS"));
  163 + assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(),
  164 + smsClient.convertSmsTemplateAuditStatus("FAIL"));
  165 + assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus("test"),
  166 + "未知审核状态(test)");
  167 + }
  168 +
  169 + @Test
  170 + public void testInvoke_throwable() {
  171 + // 准备参数
  172 + Supplier<Result<Object>> requestConsumer =
  173 + () -> new Result<>().setThrowable(new NullPointerException());
  174 + // mock 方法
  175 +
  176 + // 调用,并断言异常
  177 + assertThrows(NullPointerException.class,
  178 + () -> smsClient.invoke(requestConsumer, null));
  179 + }
  180 +
  181 + @Test
  182 + @SuppressWarnings("unchecked")
  183 + public void testInvoke_success() throws Throwable {
  184 + // 准备参数
  185 + Result<SmsSingleSend> responseResult = randomPojo(Result.class, SmsSingleSend.class, o -> o.setCode(OK));
  186 + Supplier<Result<SmsSingleSend>> requestConsumer = () -> responseResult;
  187 + Function<SmsSingleSend, SmsSendRespDTO> responseConsumer =
  188 + smsSingleSend -> new SmsSendRespDTO().setSerialNo(String.valueOf(responseResult.getData().getSid()));
  189 + // mock 方法
  190 +
  191 + // 调用
  192 + SmsCommonResult<SmsSendRespDTO> result = smsClient.invoke(requestConsumer, responseConsumer);
  193 + // 断言
  194 + assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode());
  195 + assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg());
  196 + assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
  197 + assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
  198 + assertNull(result.getApiRequestId());
  199 + assertEquals(String.valueOf(responseResult.getData().getSid()), result.getData().getSerialNo());
  200 + }
  201 +
50 } 202 }