mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-26 17:21:53 +08:00
mall + pay:
1. 完善 PayRefundServiceTest 的单元测试
This commit is contained in:
parent
9812881094
commit
ebeb14be2f
@ -19,7 +19,6 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
|||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
|
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
|
||||||
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
|
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
|
||||||
import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
|
|
||||||
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
|
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
||||||
@ -92,7 +91,6 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public Long createPayRefund(PayRefundCreateReqDTO reqDTO) {
|
public Long createPayRefund(PayRefundCreateReqDTO reqDTO) {
|
||||||
// 1.1 校验 App
|
// 1.1 校验 App
|
||||||
PayAppDO app = appService.validPayApp(reqDTO.getAppId());
|
PayAppDO app = appService.validPayApp(reqDTO.getAppId());
|
||||||
@ -109,7 +107,7 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
PayRefundDO refund = refundMapper.selectByAppIdAndMerchantRefundId(
|
PayRefundDO refund = refundMapper.selectByAppIdAndMerchantRefundId(
|
||||||
app.getId(), reqDTO.getMerchantRefundId());
|
app.getId(), reqDTO.getMerchantRefundId());
|
||||||
if (refund != null) {
|
if (refund != null) {
|
||||||
throw exception(ErrorCodeConstants.REFUND_EXISTS);
|
throw exception(REFUND_EXISTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.1 插入退款单
|
// 2.1 插入退款单
|
||||||
@ -158,7 +156,7 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
|
private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
|
||||||
PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
|
PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw exception(ErrorCodeConstants.ORDER_NOT_FOUND);
|
throw exception(ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 校验状态,必须是已支付、或者已退款
|
// 校验状态,必须是已支付、或者已退款
|
||||||
if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
|
if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
|
||||||
@ -167,12 +165,12 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
|
|
||||||
// 校验金额,退款金额不能大于原定的金额
|
// 校验金额,退款金额不能大于原定的金额
|
||||||
if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){
|
if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){
|
||||||
throw exception(ErrorCodeConstants.REFUND_PRICE_EXCEED);
|
throw exception(REFUND_PRICE_EXCEED);
|
||||||
}
|
}
|
||||||
// 是否有退款中的订单
|
// 是否有退款中的订单
|
||||||
if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(),
|
if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(),
|
||||||
PayRefundStatusEnum.WAITING.getStatus()) > 0) {
|
PayRefundStatusEnum.WAITING.getStatus()) > 0) {
|
||||||
throw exception(ErrorCodeConstants.REFUND_HAS_REFUNDING);
|
throw exception(REFUND_HAS_REFUNDING);
|
||||||
}
|
}
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package cn.iocoder.yudao.module.pay.service.refund;
|
package cn.iocoder.yudao.module.pay.service.refund;
|
||||||
|
|
||||||
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
|
import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
||||||
@ -21,12 +24,13 @@ import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
|||||||
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
|
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
|
||||||
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
|
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
|
||||||
@ -37,10 +41,12 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic
|
|||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link PayRefundServiceImpl} 的单元测试类
|
* {@link PayRefundServiceImpl} 的单元测试类
|
||||||
@ -69,6 +75,41 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
@MockBean
|
@MockBean
|
||||||
private PayNotifyService notifyService;
|
private PayNotifyService notifyService;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
when(payProperties.getRefundNotifyUrl()).thenReturn("http://127.0.0.1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetRefund() {
|
||||||
|
// mock 数据
|
||||||
|
PayRefundDO refund = randomPojo(PayRefundDO.class);
|
||||||
|
refundMapper.insert(refund);
|
||||||
|
// 准备参数
|
||||||
|
Long id = refund.getId();
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
PayRefundDO dbRefund = refundService.getRefund(id);
|
||||||
|
// 断言
|
||||||
|
assertPojoEquals(dbRefund, refund);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetRefundCountByAppId() {
|
||||||
|
// mock 数据
|
||||||
|
PayRefundDO refund01 = randomPojo(PayRefundDO.class);
|
||||||
|
refundMapper.insert(refund01);
|
||||||
|
PayRefundDO refund02 = randomPojo(PayRefundDO.class);
|
||||||
|
refundMapper.insert(refund02);
|
||||||
|
// 准备参数
|
||||||
|
Long appId = refund01.getAppId();
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
Long count = refundService.getRefundCountByAppId(appId);
|
||||||
|
// 断言
|
||||||
|
assertEquals(count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetRefundPage() {
|
public void testGetRefundPage() {
|
||||||
// mock 数据
|
// mock 数据
|
||||||
@ -276,7 +317,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
// 准备参数
|
// 准备参数
|
||||||
PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
|
PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
|
||||||
o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9)
|
o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9)
|
||||||
.setReason("测试退款"));
|
.setMerchantRefundId("200").setReason("测试退款"));
|
||||||
// mock 方法(app)
|
// mock 方法(app)
|
||||||
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
||||||
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
||||||
@ -295,7 +336,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
|
when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
|
||||||
// mock 数据(refund 已存在)
|
// mock 数据(refund 已存在)
|
||||||
PayRefundDO refund = randomPojo(PayRefundDO.class, o ->
|
PayRefundDO refund = randomPojo(PayRefundDO.class, o ->
|
||||||
o.setOrderId(order.getId()).setStatus(PayOrderStatusEnum.WAITING.getStatus()));
|
o.setAppId(1L).setMerchantRefundId("200"));
|
||||||
refundMapper.insert(refund);
|
refundMapper.insert(refund);
|
||||||
|
|
||||||
// 调用,并断言异常
|
// 调用,并断言异常
|
||||||
@ -305,12 +346,97 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateRefund_invokeException() {
|
public void testCreateRefund_invokeException() {
|
||||||
|
// 准备参数
|
||||||
|
PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
|
||||||
|
o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9)
|
||||||
|
.setMerchantRefundId("200").setReason("测试退款"));
|
||||||
|
// mock 方法(app)
|
||||||
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
||||||
|
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
||||||
|
// mock 数据(order)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o ->
|
||||||
|
o.setStatus(PayOrderStatusEnum.REFUND.getStatus())
|
||||||
|
.setPrice(10).setRefundPrice(1)
|
||||||
|
.setChannelId(10L).setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order);
|
||||||
|
// mock 方法(channel)
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
|
||||||
|
.setCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
when(channelService.validPayChannel(eq(10L))).thenReturn(channel);
|
||||||
|
// mock 方法(client)
|
||||||
|
PayClient client = mock(PayClient.class);
|
||||||
|
when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
|
||||||
|
// mock 方法(client 调用发生异常)
|
||||||
|
when(client.unifiedRefund(any(PayRefundUnifiedReqDTO.class))).thenThrow(new RuntimeException());
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
Long refundId = refundService.createPayRefund(reqDTO);
|
||||||
|
// 断言
|
||||||
|
PayRefundDO refundDO = refundMapper.selectById(refundId);
|
||||||
|
assertPojoEquals(reqDTO, refundDO);
|
||||||
|
assertNotNull(refundDO.getNo());
|
||||||
|
assertThat(refundDO)
|
||||||
|
.extracting("orderId", "orderNo", "channelId", "channelCode",
|
||||||
|
"notifyUrl", "channelOrderNo", "status", "payPrice", "refundPrice")
|
||||||
|
.containsExactly(order.getId(), order.getNo(), channel.getId(), channel.getCode(),
|
||||||
|
app.getRefundNotifyUrl(), order.getChannelOrderNo(), PayRefundStatusEnum.WAITING.getStatus(),
|
||||||
|
order.getPrice(), reqDTO.getPrice());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateRefund_invokeSuccess() {
|
public void testCreateRefund_invokeSuccess() {
|
||||||
|
PayRefundServiceImpl payRefundServiceImpl = mock(PayRefundServiceImpl.class);
|
||||||
|
try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
|
||||||
|
springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayRefundServiceImpl.class)))
|
||||||
|
.thenReturn(payRefundServiceImpl);
|
||||||
|
|
||||||
|
// 准备参数
|
||||||
|
PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
|
||||||
|
o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9)
|
||||||
|
.setMerchantRefundId("200").setReason("测试退款"));
|
||||||
|
// mock 方法(app)
|
||||||
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
||||||
|
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
||||||
|
// mock 数据(order)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o ->
|
||||||
|
o.setStatus(PayOrderStatusEnum.REFUND.getStatus())
|
||||||
|
.setPrice(10).setRefundPrice(1)
|
||||||
|
.setChannelId(10L).setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order);
|
||||||
|
// mock 方法(channel)
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
|
||||||
|
.setCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
when(channelService.validPayChannel(eq(10L))).thenReturn(channel);
|
||||||
|
// mock 方法(client)
|
||||||
|
PayClient client = mock(PayClient.class);
|
||||||
|
when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
|
||||||
|
// mock 方法(client 成功)
|
||||||
|
PayRefundRespDTO refundRespDTO = randomPojo(PayRefundRespDTO.class);
|
||||||
|
when(client.unifiedRefund(argThat(unifiedReqDTO -> {
|
||||||
|
assertNotNull(unifiedReqDTO.getOutRefundNo());
|
||||||
|
assertThat(unifiedReqDTO)
|
||||||
|
.extracting("payPrice", "refundPrice", "outTradeNo",
|
||||||
|
"notifyUrl", "reason")
|
||||||
|
.containsExactly(order.getPrice(), reqDTO.getPrice(), order.getNo(),
|
||||||
|
"http://127.0.0.1/10", reqDTO.getReason());
|
||||||
|
return true;
|
||||||
|
}))).thenReturn(refundRespDTO);
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
Long refundId = refundService.createPayRefund(reqDTO);
|
||||||
|
// 断言
|
||||||
|
PayRefundDO refundDO = refundMapper.selectById(refundId);
|
||||||
|
assertPojoEquals(reqDTO, refundDO);
|
||||||
|
assertNotNull(refundDO.getNo());
|
||||||
|
assertThat(refundDO)
|
||||||
|
.extracting("orderId", "orderNo", "channelId", "channelCode",
|
||||||
|
"notifyUrl", "channelOrderNo", "status", "payPrice", "refundPrice")
|
||||||
|
.containsExactly(order.getId(), order.getNo(), channel.getId(), channel.getCode(),
|
||||||
|
app.getRefundNotifyUrl(), order.getChannelOrderNo(), PayRefundStatusEnum.WAITING.getStatus(),
|
||||||
|
order.getPrice(), reqDTO.getPrice());
|
||||||
|
// 断言调用
|
||||||
|
verify(payRefundServiceImpl).notifyRefund(same(channel), same(refundRespDTO));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,7 @@ CREATE TABLE IF NOT EXISTS `pay_refund` (
|
|||||||
`channel_id` bigint(20) NOT NULL,
|
`channel_id` bigint(20) NOT NULL,
|
||||||
`channel_code` varchar(32) NOT NULL,
|
`channel_code` varchar(32) NOT NULL,
|
||||||
`order_id` bigint(20) NOT NULL,
|
`order_id` bigint(20) NOT NULL,
|
||||||
|
`order_no` varchar(64) NOT NULL,
|
||||||
`merchant_order_id` varchar(64) NOT NULL,
|
`merchant_order_id` varchar(64) NOT NULL,
|
||||||
`merchant_refund_id` varchar(64) NOT NULL,
|
`merchant_refund_id` varchar(64) NOT NULL,
|
||||||
`notify_url` varchar(1024) NOT NULL,
|
`notify_url` varchar(1024) NOT NULL,
|
||||||
|
Loading…
Reference in New Issue
Block a user