by gateway:

1. notify 部分单元测试
This commit is contained in:
zhijiantianya@gmail.com
2023-07-24 20:11:21 +08:00
parent 00e1c30f57
commit 73e1158836
14 changed files with 238 additions and 66 deletions

View File

@@ -0,0 +1,184 @@
package cn.iocoder.yudao.module.pay.service.notify;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
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.mysql.notify.PayNotifyLogMapper;
import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper;
import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO;
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
import cn.iocoder.yudao.module.pay.framework.job.config.PayJobConfiguration;
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
import cn.iocoder.yudao.module.pay.service.refund.PayRefundServiceImpl;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import javax.annotation.Resource;
import java.time.Duration;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
/**
* {@link PayRefundServiceImpl} 的单元测试类
*
* @author 芋艿
*/
@Import({PayJobConfiguration.class, PayNotifyServiceImpl.class, PayNotifyLockRedisDAO.class})
public class PayNotifyServiceTest extends BaseDbUnitTest {
@Resource
private PayNotifyServiceImpl notifyService;
@MockBean
private PayOrderService orderService;
@MockBean
private PayRefundService refundService;
@Resource
private PayNotifyTaskMapper notifyTaskMapper;
@Resource
private PayNotifyLogMapper notifyLogMapper;
@MockBean
private RedissonClient redissonClient;
@Test
public void testCreatePayNotifyTask_order() {
PayNotifyServiceImpl payNotifyService = mock(PayNotifyServiceImpl.class);
try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayNotifyServiceImpl.class)))
.thenReturn(payNotifyService);
// 准备参数
Integer type = PayNotifyTypeEnum.ORDER.getType();
Long dataId = 1L;
// mock 方法(order)
PayOrderDO order = randomPojo(PayOrderDO.class);
when(orderService.getOrder(eq(1L))).thenReturn(order);
// mock 方法lock
mockLock(null); // null 的原因,是咱没办法拿到 taskId 新增
// 调用
notifyService.createPayNotifyTask(type, dataId);
// 断言task
PayNotifyTaskDO dbTask = notifyTaskMapper.selectOne(null);
assertNotNull(dbTask.getNextNotifyTime());
assertThat(dbTask)
.extracting("type", "dataId", "status", "notifyTimes", "maxNotifyTimes",
"appId", "merchantOrderId", "notifyUrl")
.containsExactly(type, dataId, PayNotifyStatusEnum.WAITING.getStatus(), 0, 9,
order.getAppId(), order.getMerchantOrderId(), order.getNotifyUrl());
// 断言,调用
verify(payNotifyService).executeNotify0(eq(dbTask));
}
}
@Test
public void testCreatePayNotifyTask_refund() {
PayNotifyServiceImpl payNotifyService = mock(PayNotifyServiceImpl.class);
try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayNotifyServiceImpl.class)))
.thenReturn(payNotifyService);
// 准备参数
Integer type = PayNotifyTypeEnum.REFUND.getType();
Long dataId = 1L;
// mock 方法(refund)
PayRefundDO refund = randomPojo(PayRefundDO.class);
when(refundService.getRefund(eq(1L))).thenReturn(refund);
// mock 方法lock
mockLock(null); // null 的原因,是咱没办法拿到 taskId 新增
// 调用
notifyService.createPayNotifyTask(type, dataId);
// 断言task
PayNotifyTaskDO dbTask = notifyTaskMapper.selectOne(null);
assertNotNull(dbTask.getNextNotifyTime());
assertThat(dbTask)
.extracting("type", "dataId", "status", "notifyTimes", "maxNotifyTimes",
"appId", "merchantOrderId", "notifyUrl")
.containsExactly(type, dataId, PayNotifyStatusEnum.WAITING.getStatus(), 0, 9,
refund.getAppId(), refund.getMerchantOrderId(), refund.getNotifyUrl());
// 断言,调用
verify(payNotifyService).executeNotify0(eq(dbTask));
}
}
@Test
public void testExecuteNotify() throws InterruptedException {
// mock 数据notify
PayNotifyTaskDO dbTask01 = randomPojo(PayNotifyTaskDO.class,
o -> o.setStatus(PayNotifyStatusEnum.WAITING.getStatus())
.setNextNotifyTime(addTime(Duration.ofMinutes(-1))));
notifyTaskMapper.insert(dbTask01);
PayNotifyTaskDO dbTask02 = randomPojo(PayNotifyTaskDO.class,
o -> o.setStatus(PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus())
.setNextNotifyTime(addTime(Duration.ofMinutes(-1))));
notifyTaskMapper.insert(dbTask02);
PayNotifyTaskDO dbTask03 = randomPojo(PayNotifyTaskDO.class,
o -> o.setStatus(PayNotifyStatusEnum.REQUEST_FAILURE.getStatus())
.setNextNotifyTime(addTime(Duration.ofMinutes(-1))));
notifyTaskMapper.insert(dbTask03);
PayNotifyTaskDO dbTask04 = randomPojo(PayNotifyTaskDO.class, // 不满足状态
o -> o.setStatus(PayNotifyStatusEnum.FAILURE.getStatus())
.setNextNotifyTime(addTime(Duration.ofMinutes(-1))));
notifyTaskMapper.insert(dbTask04);
PayNotifyTaskDO dbTask05 = randomPojo(PayNotifyTaskDO.class, // 不满足状态
o -> o.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus())
.setNextNotifyTime(addTime(Duration.ofMinutes(-1))));
notifyTaskMapper.insert(dbTask05);
PayNotifyTaskDO dbTask06 = randomPojo(PayNotifyTaskDO.class, // 不满足时间
o -> o.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus())
.setNextNotifyTime(addTime(Duration.ofMinutes(1))));
notifyTaskMapper.insert(dbTask06);
// mock 方法lock
mockLock(dbTask01.getId());
mockLock(dbTask02.getId());
mockLock(dbTask03.getId());
// 调用
int count = notifyService.executeNotify();
// 断言,数量
assertEquals(count, 3);
}
@Test // 由于 HttpUtil 不好 mock所以只测试异常的情况
public void testExecuteNotify0_exception() {
// mock 数据task
PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class, o -> o.setType(-1)
.setNotifyTimes(0).setMaxNotifyTimes(9));
notifyTaskMapper.insert(task);
// 调用
notifyService.executeNotify0(task);
}
private void mockLock(Long id) {
RLock lock = mock(RLock.class);
if (id == null) {
when(redissonClient.getLock(anyString()))
.thenReturn(lock);
} else {
when(redissonClient.getLock(eq("pay_notify:lock:" + id)))
.thenReturn(lock);
}
}
}

View File

@@ -27,7 +27,6 @@ import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
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.notify.PayNotifyService;
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
@@ -622,7 +621,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
// 断言 PayOrderDO :数据未更新,因为它是 SUCCESS
assertPojoEquals(order, orderMapper.selectOne(null));
// 断言,调用
verify(notifyService, never()).createPayNotifyTask(any(PayNotifyTaskCreateReqDTO.class));
verify(notifyService, never()).createPayNotifyTask(anyInt(), anyLong());
}
@Test
@@ -661,11 +660,8 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
assertPojoEquals(order, orderMapper.selectOne(null),
"updateTime", "updater");
// 断言,调用
verify(notifyService).createPayNotifyTask(argThat(reqDTO -> {
assertEquals(reqDTO.getType(), PayNotifyTypeEnum.ORDER.getType());
assertEquals(reqDTO.getDataId(), orderExtension.getOrderId());
return true;
}));
verify(notifyService).createPayNotifyTask(eq(PayNotifyTypeEnum.ORDER.getType()),
eq(orderExtension.getOrderId()));
}
@Test

View File

@@ -25,7 +25,6 @@ import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
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.notify.PayNotifyService;
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -552,8 +551,8 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
"updateTime", "updater");
// 断言,调用
verify(orderService).updateOrderRefundPrice(eq(100L), eq(23));
verify(notifyService).createPayNotifyTask(eq(PayNotifyTaskCreateReqDTO.builder()
.type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build()));
verify(notifyService).createPayNotifyTask(eq(PayNotifyTypeEnum.REFUND.getType()),
eq(refund.getId()));
}
@Test
@@ -624,8 +623,8 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
assertPojoEquals(refund, refundMapper.selectById(refund.getId()),
"updateTime", "updater");
// 断言,调用
verify(notifyService).createPayNotifyTask(eq(PayNotifyTaskCreateReqDTO.builder()
.type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build()));
verify(notifyService).createPayNotifyTask(eq(PayNotifyTypeEnum.REFUND.getType()),
eq(refund.getId()));
}
@Test

View File

@@ -3,3 +3,4 @@ DELETE FROM pay_channel;
DELETE FROM pay_order;
DELETE FROM pay_order_extension;
DELETE FROM pay_refund;
DELETE FROM pay_notify_task;

View File

@@ -109,3 +109,24 @@ CREATE TABLE IF NOT EXISTS `pay_refund` (
`deleted` bit(1) NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT = '退款订单';
CREATE TABLE IF NOT EXISTS `pay_notify_task` (
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
`app_id` bigint(20) NOT NULL,
`type` tinyint(4) NOT NULL,
`data_id` bigint(20) NOT NULL,
`merchant_order_id` varchar(64) NOT NULL,
`status` tinyint(4) NOT NULL,
`next_notify_time` datetime(0) NULL DEFAULT NULL,
`last_execute_time` datetime(0) NULL DEFAULT NULL,
`notify_times` int NOT NULL,
`max_notify_times` int NOT NULL,
`notify_url` varchar(1024) NOT NULL,
`creator` varchar(64) NULL DEFAULT '',
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updater` varchar(64) NULL DEFAULT '',
`update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`deleted` bit(1) NOT NULL DEFAULT FALSE,
`tenant_id` bigint(20) NOT NULL DEFAULT 0,
PRIMARY KEY ("id")
) COMMENT = '支付通知';