Commit 6fbf7b261b49b63ec68047822ed68c90f16ffe3c

Authored by jason
1 parent d3c02f2a

扫码支付统一退款单元测试, 修复退款失败,渠道错误未赋值bug

yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
@@ -148,7 +148,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa @@ -148,7 +148,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
148 // 2.1 执行请求 148 // 2.1 执行请求
149 AlipayTradeRefundResponse response = client.execute(request); 149 AlipayTradeRefundResponse response = client.execute(request);
150 if (!response.isSuccess()) { 150 if (!response.isSuccess()) {
151 - return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response); 151 + return PayRefundRespDTO.failureOf(response.getSubCode(), response.getSubMsg(), reqDTO.getOutRefundNo(), response);
152 } 152 }
153 // 2.2 创建返回结果 153 // 2.2 创建返回结果
154 // 支付宝只要退款调用返回 success,就认为退款成功,不需要回调。具体可见 parseNotify 方法的说明。 154 // 支付宝只要退款调用返回 success,就认为退款成功,不需要回调。具体可见 parseNotify 方法的说明。
yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java
1 package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; 1 package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
2 2
  3 +import cn.hutool.core.date.LocalDateTimeUtil;
3 import cn.hutool.core.util.RandomUtil; 4 import cn.hutool.core.util.RandomUtil;
4 import cn.hutool.core.util.ReflectUtil; 5 import cn.hutool.core.util.ReflectUtil;
5 import cn.iocoder.yudao.framework.common.exception.ServiceException; 6 import cn.iocoder.yudao.framework.common.exception.ServiceException;
@@ -7,19 +8,27 @@ import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstant @@ -7,19 +8,27 @@ import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstant
7 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; 8 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
8 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 9 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
9 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 10 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
  11 +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
  12 +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
10 import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; 13 import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
11 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; 14 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
  15 +import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
12 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; 16 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
13 import com.alipay.api.AlipayApiException; 17 import com.alipay.api.AlipayApiException;
14 import com.alipay.api.DefaultAlipayClient; 18 import com.alipay.api.DefaultAlipayClient;
  19 +import com.alipay.api.domain.AlipayTradeRefundModel;
15 import com.alipay.api.request.AlipayTradePrecreateRequest; 20 import com.alipay.api.request.AlipayTradePrecreateRequest;
  21 +import com.alipay.api.request.AlipayTradeRefundRequest;
16 import com.alipay.api.response.AlipayTradePrecreateResponse; 22 import com.alipay.api.response.AlipayTradePrecreateResponse;
  23 +import com.alipay.api.response.AlipayTradeRefundResponse;
  24 +import org.junit.jupiter.api.DisplayName;
17 import org.junit.jupiter.api.Test; 25 import org.junit.jupiter.api.Test;
18 import org.mockito.ArgumentMatcher; 26 import org.mockito.ArgumentMatcher;
19 import org.mockito.InjectMocks; 27 import org.mockito.InjectMocks;
20 import org.mockito.Mock; 28 import org.mockito.Mock;
21 29
22 import javax.validation.ConstraintViolationException; 30 import javax.validation.ConstraintViolationException;
  31 +import java.util.Date;
23 32
24 import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_PUBLIC_KEY; 33 import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_PUBLIC_KEY;
25 import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED; 34 import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED;
@@ -51,13 +60,14 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { @@ -51,13 +60,14 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest {
51 private DefaultAlipayClient defaultAlipayClient; 60 private DefaultAlipayClient defaultAlipayClient;
52 61
53 @Test 62 @Test
54 - public void testDoInit() { 63 + public void test_do_init() {
55 client.doInit(); 64 client.doInit();
56 assertNotSame(defaultAlipayClient, ReflectUtil.getFieldValue(client, "defaultAlipayClient")); 65 assertNotSame(defaultAlipayClient, ReflectUtil.getFieldValue(client, "defaultAlipayClient"));
57 } 66 }
58 67
59 @Test 68 @Test
60 - public void testUnifiedOrderSuccess() throws AlipayApiException { 69 + @DisplayName("支付包扫描支付下单成功")
  70 + public void test_unified_order_success() throws AlipayApiException {
61 // 准备返回对象 71 // 准备返回对象
62 String notifyUrl = randomURL(); 72 String notifyUrl = randomURL();
63 String qrCode = randomString(); 73 String qrCode = randomString();
@@ -84,7 +94,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { @@ -84,7 +94,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest {
84 } 94 }
85 95
86 @Test 96 @Test
87 - public void testUnifiedOrderChannelFailed() throws AlipayApiException { 97 + @DisplayName("支付包扫描支付,渠道返回失败")
  98 + public void test_unified_order_channel_failed() throws AlipayApiException {
88 String notifyUrl = randomURL(); 99 String notifyUrl = randomURL();
89 String subCode = randomString(); 100 String subCode = randomString();
90 String subMsg = randomString(); 101 String subMsg = randomString();
@@ -110,7 +121,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { @@ -110,7 +121,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest {
110 } 121 }
111 122
112 @Test 123 @Test
113 - public void test_unifiedOrder_throw_pay_exception() throws AlipayApiException { 124 + @DisplayName("支付包扫描支付,抛出系统异常")
  125 + public void test_unified_order_throw_pay_exception() throws AlipayApiException {
114 // 准备请求参数 126 // 准备请求参数
115 String outTradeNo = randomString(); 127 String outTradeNo = randomString();
116 String notifyUrl = randomURL(); 128 String notifyUrl = randomURL();
@@ -126,7 +138,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { @@ -126,7 +138,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest {
126 } 138 }
127 139
128 @Test 140 @Test
129 - public void test_unifiedOrder_throw_service_exception() throws AlipayApiException { 141 + @DisplayName("支付包扫描支付,抛出业务异常")
  142 + public void test_unified_order_throw_service_exception() throws AlipayApiException {
130 // 准备请求参数 143 // 准备请求参数
131 String outTradeNo = randomString(); 144 String outTradeNo = randomString();
132 String notifyUrl = randomURL(); 145 String notifyUrl = randomURL();
@@ -142,7 +155,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { @@ -142,7 +155,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest {
142 } 155 }
143 156
144 @Test 157 @Test
145 - public void test_unifiedOrder_param_validate() { 158 + @DisplayName("支付包扫描支付,参数校验不通过")
  159 + public void test_unified_order_param_validate() {
146 // 准备请求参数 160 // 准备请求参数
147 String outTradeNo = randomString(); 161 String outTradeNo = randomString();
148 String notifyUrl = randomURL(); 162 String notifyUrl = randomURL();
@@ -162,4 +176,119 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { @@ -162,4 +176,119 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest {
162 o.setBody(RandomUtil.randomString(32)); 176 o.setBody(RandomUtil.randomString(32));
163 }); 177 });
164 } 178 }
  179 +
  180 + @Test
  181 + @DisplayName("支付包扫描退款成功")
  182 + public void test_unified_refund_success() throws AlipayApiException {
  183 + // 准备返回对象
  184 + String notifyUrl = randomURL();
  185 + Date refundTime = randomDate();
  186 + String outRefundNo = randomString();
  187 + String outTradeNo = randomString();
  188 + Integer refundAmount = randomInteger();
  189 + AlipayTradeRefundResponse response = randomPojo(AlipayTradeRefundResponse.class, o -> {
  190 + o.setSubCode("");
  191 + o.setGmtRefundPay(refundTime);
  192 + });
  193 + // mock
  194 + when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> {
  195 + assertInstanceOf(AlipayTradeRefundModel.class, request.getBizModel());
  196 + AlipayTradeRefundModel bizModel = (AlipayTradeRefundModel) request.getBizModel();
  197 + assertEquals(outRefundNo, bizModel.getOutRequestNo());
  198 + assertEquals(outTradeNo, bizModel.getOutTradeNo());
  199 + assertEquals(String.valueOf(refundAmount / 100.0), bizModel.getRefundAmount());
  200 + return true;
  201 + }))).thenReturn(response);
  202 + // 准备请求参数
  203 + PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
  204 + o.setOutRefundNo(outRefundNo);
  205 + o.setOutTradeNo(outTradeNo);
  206 + o.setNotifyUrl(notifyUrl);
  207 + o.setRefundPrice(refundAmount);
  208 + });
  209 + PayRefundRespDTO resp = client.unifiedRefund(refundReqDTO);
  210 + // 断言
  211 + assertEquals(PayRefundStatusRespEnum.SUCCESS.getStatus(), resp.getStatus());
  212 + assertNull(resp.getChannelRefundNo());
  213 + assertEquals(LocalDateTimeUtil.of(refundTime), resp.getSuccessTime());
  214 + assertEquals(outRefundNo, resp.getOutRefundNo());
  215 + assertSame(response, resp.getRawData());
  216 + }
  217 +
  218 + @Test
  219 + @DisplayName("支付包扫描退款,渠道返回失败")
  220 + public void test_unified_refund_channel_failed() throws AlipayApiException {
  221 + // 准备返回对象
  222 + String notifyUrl = randomURL();
  223 + String subCode = randomString();
  224 + String subMsg = randomString();
  225 + AlipayTradeRefundResponse response = randomPojo(AlipayTradeRefundResponse.class, o -> {
  226 + o.setSubCode(subCode);
  227 + o.setSubMsg(subMsg);
  228 + });
  229 + // mock
  230 + when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> {
  231 + assertInstanceOf(AlipayTradeRefundModel.class, request.getBizModel());
  232 + return true;
  233 + }))).thenReturn(response);
  234 + // 准备请求参数
  235 + String outRefundNo = randomString();
  236 + String outTradeNo = randomString();
  237 + PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
  238 + o.setOutRefundNo(outRefundNo);
  239 + o.setOutTradeNo(outTradeNo);
  240 + o.setNotifyUrl(notifyUrl);
  241 + });
  242 + PayRefundRespDTO resp = client.unifiedRefund(refundReqDTO);
  243 + // 断言
  244 + assertEquals(PayRefundStatusRespEnum.FAILURE.getStatus(), resp.getStatus());
  245 + assertNull(resp.getChannelRefundNo());
  246 + assertEquals(subCode, resp.getChannelErrorCode());
  247 + assertEquals(subMsg, resp.getChannelErrorMsg());
  248 + assertNull(resp.getSuccessTime());
  249 + assertEquals(outRefundNo, resp.getOutRefundNo());
  250 + assertSame(response, resp.getRawData());
  251 + }
  252 +
  253 + @Test
  254 + @DisplayName("支付包扫描退款,参数校验不通过")
  255 + public void test_unified_refund_param_validate() {
  256 + // 准备请求参数
  257 + String notifyUrl = randomURL();
  258 + PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
  259 + o.setOutTradeNo("");
  260 + o.setNotifyUrl(notifyUrl);
  261 + });
  262 + // 断言
  263 + assertThrows(ConstraintViolationException.class, () -> client.unifiedRefund(refundReqDTO));
  264 + }
  265 +
  266 + @Test
  267 + @DisplayName("支付包扫描退款,抛出业务异常")
  268 + public void test_unified_refund_throw_service_exception() throws AlipayApiException {
  269 + // mock
  270 + when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> true)))
  271 + .thenThrow(ServiceExceptionUtil.exception(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR));
  272 + // 准备请求参数
  273 + String notifyUrl = randomURL();
  274 + PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
  275 + o.setNotifyUrl(notifyUrl);
  276 + });
  277 + // 断言
  278 + assertThrows(ServiceException.class, () -> client.unifiedRefund(refundReqDTO));
  279 + }
  280 + @Test
  281 + @DisplayName("支付包扫描退款,抛出系统异常")
  282 + public void test_unified_refund_throw_pay_exception() throws AlipayApiException {
  283 + // mock
  284 + when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> true)))
  285 + .thenThrow(new RuntimeException("系统异常"));
  286 + // 准备请求参数
  287 + String notifyUrl = randomURL();
  288 + PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
  289 + o.setNotifyUrl(notifyUrl);
  290 + });
  291 + // 断言
  292 + assertThrows(PayException.class, () -> client.unifiedRefund(refundReqDTO));
  293 + }
165 } 294 }
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/decorate/DecorateComponentServiceImplTest.java
@@ -7,16 +7,14 @@ import org.junit.jupiter.api.BeforeEach; @@ -7,16 +7,14 @@ import org.junit.jupiter.api.BeforeEach;
7 import org.junit.jupiter.api.Test; 7 import org.junit.jupiter.api.Test;
8 import org.mockito.InjectMocks; 8 import org.mockito.InjectMocks;
9 import org.mockito.Mock; 9 import org.mockito.Mock;
10 -import org.mockito.Mockito;  
11 10
12 import java.util.ArrayList; 11 import java.util.ArrayList;
13 import java.util.List; 12 import java.util.List;
14 13
15 import static cn.iocoder.yudao.module.promotion.enums.decorate.DecorateComponentEnum.ROLLING_NEWS; 14 import static cn.iocoder.yudao.module.promotion.enums.decorate.DecorateComponentEnum.ROLLING_NEWS;
16 import static cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageEnum.INDEX; 15 import static cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageEnum.INDEX;
17 -import static org.mockito.ArgumentMatchers.eq;  
18 16
19 -// TODO @芋艿:后续 review 下 17 +// TODO 待完成 @芋艿:后续 review 下
20 /** 18 /**
21 * @author jason 19 * @author jason
22 */ 20 */
@@ -41,6 +39,6 @@ public class DecorateComponentServiceImplTest extends BaseMockitoUnitTest { @@ -41,6 +39,6 @@ public class DecorateComponentServiceImplTest extends BaseMockitoUnitTest {
41 .setCode(ROLLING_NEWS.getCode()).setId(1L); 39 .setCode(ROLLING_NEWS.getCode()).setId(1L);
42 list.add(decorateDO); 40 list.add(decorateDO);
43 //mock 方法 41 //mock 方法
44 - Mockito.when(decorateComponentMapper.selectListByPageAndStatus(eq(1))).thenReturn(list); 42 + //Mockito.when(decorateComponentMapper.selectListByPageAndStatus(eq(1))).thenReturn(list);
45 } 43 }
46 } 44 }