Commit 6fbf7b261b49b63ec68047822ed68c90f16ffe3c
1 parent
d3c02f2a
扫码支付统一退款单元测试, 修复退款失败,渠道错误未赋值bug
Showing
3 changed files
with
138 additions
and
11 deletions
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 | 148 | // 2.1 执行请求 |
| 149 | 149 | AlipayTradeRefundResponse response = client.execute(request); |
| 150 | 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 | 153 | // 2.2 创建返回结果 |
| 154 | 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 | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.date.LocalDateTimeUtil; | |
| 3 | 4 | import cn.hutool.core.util.RandomUtil; |
| 4 | 5 | import cn.hutool.core.util.ReflectUtil; |
| 5 | 6 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| ... | ... | @@ -7,19 +8,27 @@ import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstant |
| 7 | 8 | import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; |
| 8 | 9 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 9 | 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 | 13 | import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; |
| 11 | 14 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 15 | +import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; | |
| 12 | 16 | import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; |
| 13 | 17 | import com.alipay.api.AlipayApiException; |
| 14 | 18 | import com.alipay.api.DefaultAlipayClient; |
| 19 | +import com.alipay.api.domain.AlipayTradeRefundModel; | |
| 15 | 20 | import com.alipay.api.request.AlipayTradePrecreateRequest; |
| 21 | +import com.alipay.api.request.AlipayTradeRefundRequest; | |
| 16 | 22 | import com.alipay.api.response.AlipayTradePrecreateResponse; |
| 23 | +import com.alipay.api.response.AlipayTradeRefundResponse; | |
| 24 | +import org.junit.jupiter.api.DisplayName; | |
| 17 | 25 | import org.junit.jupiter.api.Test; |
| 18 | 26 | import org.mockito.ArgumentMatcher; |
| 19 | 27 | import org.mockito.InjectMocks; |
| 20 | 28 | import org.mockito.Mock; |
| 21 | 29 | |
| 22 | 30 | import javax.validation.ConstraintViolationException; |
| 31 | +import java.util.Date; | |
| 23 | 32 | |
| 24 | 33 | import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_PUBLIC_KEY; |
| 25 | 34 | import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED; |
| ... | ... | @@ -51,13 +60,14 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { |
| 51 | 60 | private DefaultAlipayClient defaultAlipayClient; |
| 52 | 61 | |
| 53 | 62 | @Test |
| 54 | - public void testDoInit() { | |
| 63 | + public void test_do_init() { | |
| 55 | 64 | client.doInit(); |
| 56 | 65 | assertNotSame(defaultAlipayClient, ReflectUtil.getFieldValue(client, "defaultAlipayClient")); |
| 57 | 66 | } |
| 58 | 67 | |
| 59 | 68 | @Test |
| 60 | - public void testUnifiedOrderSuccess() throws AlipayApiException { | |
| 69 | + @DisplayName("支付包扫描支付下单成功") | |
| 70 | + public void test_unified_order_success() throws AlipayApiException { | |
| 61 | 71 | // 准备返回对象 |
| 62 | 72 | String notifyUrl = randomURL(); |
| 63 | 73 | String qrCode = randomString(); |
| ... | ... | @@ -84,7 +94,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { |
| 84 | 94 | } |
| 85 | 95 | |
| 86 | 96 | @Test |
| 87 | - public void testUnifiedOrderChannelFailed() throws AlipayApiException { | |
| 97 | + @DisplayName("支付包扫描支付,渠道返回失败") | |
| 98 | + public void test_unified_order_channel_failed() throws AlipayApiException { | |
| 88 | 99 | String notifyUrl = randomURL(); |
| 89 | 100 | String subCode = randomString(); |
| 90 | 101 | String subMsg = randomString(); |
| ... | ... | @@ -110,7 +121,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { |
| 110 | 121 | } |
| 111 | 122 | |
| 112 | 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 | 127 | String outTradeNo = randomString(); |
| 116 | 128 | String notifyUrl = randomURL(); |
| ... | ... | @@ -126,7 +138,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { |
| 126 | 138 | } |
| 127 | 139 | |
| 128 | 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 | 144 | String outTradeNo = randomString(); |
| 132 | 145 | String notifyUrl = randomURL(); |
| ... | ... | @@ -142,7 +155,8 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { |
| 142 | 155 | } |
| 143 | 156 | |
| 144 | 157 | @Test |
| 145 | - public void test_unifiedOrder_param_validate() { | |
| 158 | + @DisplayName("支付包扫描支付,参数校验不通过") | |
| 159 | + public void test_unified_order_param_validate() { | |
| 146 | 160 | // 准备请求参数 |
| 147 | 161 | String outTradeNo = randomString(); |
| 148 | 162 | String notifyUrl = randomURL(); |
| ... | ... | @@ -162,4 +176,119 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { |
| 162 | 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 | 7 | import org.junit.jupiter.api.Test; |
| 8 | 8 | import org.mockito.InjectMocks; |
| 9 | 9 | import org.mockito.Mock; |
| 10 | -import org.mockito.Mockito; | |
| 11 | 10 | |
| 12 | 11 | import java.util.ArrayList; |
| 13 | 12 | import java.util.List; |
| 14 | 13 | |
| 15 | 14 | import static cn.iocoder.yudao.module.promotion.enums.decorate.DecorateComponentEnum.ROLLING_NEWS; |
| 16 | 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 | 19 | * @author jason |
| 22 | 20 | */ |
| ... | ... | @@ -41,6 +39,6 @@ public class DecorateComponentServiceImplTest extends BaseMockitoUnitTest { |
| 41 | 39 | .setCode(ROLLING_NEWS.getCode()).setId(1L); |
| 42 | 40 | list.add(decorateDO); |
| 43 | 41 | //mock 方法 |
| 44 | - Mockito.when(decorateComponentMapper.selectListByPageAndStatus(eq(1))).thenReturn(list); | |
| 42 | + //Mockito.when(decorateComponentMapper.selectListByPageAndStatus(eq(1))).thenReturn(list); | |
| 45 | 43 | } |
| 46 | 44 | } | ... | ... |