Переглянути джерело

1. 完善 PayNotifyServiceImpl 的单元测试

YunaiV 1 рік тому
батько
коміт
7c165fb1f6

+ 2 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskPageReqVO.java

@@ -21,13 +21,13 @@ public class PayNotifyTaskPageReqVO extends PageParam {
     private Long appId;
 
     @Schema(description = "通知类型", example = "2")
-    private Byte type;
+    private Integer type;
 
     @Schema(description = "数据编号", example = "6722")
     private Long dataId;
 
     @Schema(description = "通知状态", example = "1")
-    private Byte status;
+    private Integer status;
 
     @Schema(description = "商户订单编号", example = "26697")
     private String merchantOrderId;

+ 4 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java

@@ -25,6 +25,7 @@ import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
+import com.google.common.annotations.VisibleForTesting;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@@ -177,7 +178,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
         });
     }
 
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     public void executeNotify0(PayNotifyTaskDO task) {
         // 发起回调
         CommonResult<?> invokeResult = null;
@@ -237,7 +238,8 @@ public class PayNotifyServiceImpl implements PayNotifyService {
      * @param invokeException 通知异常
      * @return 最终任务的状态
      */
-    private Integer processNotifyResult(PayNotifyTaskDO task, CommonResult<?> invokeResult, Throwable invokeException) {
+    @VisibleForTesting
+    Integer processNotifyResult(PayNotifyTaskDO task, CommonResult<?> invokeResult, Throwable invokeException) {
         // 设置通用的更新 PayNotifyTaskDO 的字段
         PayNotifyTaskDO updateTask = new PayNotifyTaskDO()
                 .setId(task.getId())

+ 170 - 3
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceTest.java

@@ -1,7 +1,11 @@
 package cn.iocoder.yudao.module.pay.service.notify;
 
 import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
+import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
 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;
@@ -20,14 +24,17 @@ 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 java.util.List;
 
-import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
+import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -167,7 +174,167 @@ public class PayNotifyServiceTest extends BaseDbUnitTest {
 
         // 调用
         notifyService.executeNotify0(task);
+        // 断言,task
+        PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId());
+        assertNotEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime());
+        assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime());
+        assertEquals(dbTask.getNotifyTimes(), 1);
+        assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.REQUEST_FAILURE.getStatus());
+        // 断言,log
+        PayNotifyLogDO dbLog = notifyLogMapper.selectOne(null);
+        assertEquals(dbLog.getTaskId(), task.getId());
+        assertEquals(dbLog.getNotifyTimes(), 1);
+        assertTrue(dbLog.getResponse().contains("未知的通知任务类型:"));
+        assertEquals(dbLog.getStatus(), PayNotifyStatusEnum.REQUEST_FAILURE.getStatus());
+    }
+
+    @Test
+    public void testProcessNotifyResult_success() {
+        // mock 数据(task)
+        PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class,
+                o -> o.setNotifyTimes(0).setMaxNotifyTimes(9));
+        notifyTaskMapper.insert(task);
+        // 准备参数
+        CommonResult<?> invokeResult = CommonResult.success(randomString());
+
+        // 调用
+        notifyService.processNotifyResult(task, invokeResult, null);
+        // 断言
+        PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId());
+        assertEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime());
+        assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime());
+        assertEquals(dbTask.getNotifyTimes(), 1);
+        assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.SUCCESS.getStatus());
+    }
+
+    @Test
+    public void testProcessNotifyResult_failure() {
+        // mock 数据(task)
+        PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class,
+                o -> o.setNotifyTimes(8).setMaxNotifyTimes(9));
+        notifyTaskMapper.insert(task);
+        // 准备参数
+        CommonResult<?> invokeResult = CommonResult.error(BAD_REQUEST);
+
+        // 调用
+        notifyService.processNotifyResult(task, invokeResult, null);
+        // 断言
+        PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId());
+        assertEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime());
+        assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime());
+        assertEquals(dbTask.getNotifyTimes(), 9);
+        assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.FAILURE.getStatus());
+    }
+
+    @Test
+    public void testProcessNotifyResult_requestFailure() {
+        // mock 数据(task)
+        PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class,
+                o -> o.setNotifyTimes(0).setMaxNotifyTimes(9));
+        notifyTaskMapper.insert(task);
+        // 准备参数
+        CommonResult<?> invokeResult = CommonResult.error(BAD_REQUEST);
+
+        // 调用
+        notifyService.processNotifyResult(task, invokeResult, null);
+        // 断言
+        PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId());
+        assertNotEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime());
+        assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime());
+        assertEquals(dbTask.getNotifyTimes(), 1);
+        assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus());
+    }
 
+    @Test
+    public void testProcessNotifyResult_requestSuccess() {
+        // mock 数据(task)
+        PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class,
+                o -> o.setNotifyTimes(0).setMaxNotifyTimes(9));
+        notifyTaskMapper.insert(task);
+        // 准备参数
+        CommonResult<?> invokeResult = CommonResult.error(BAD_REQUEST);
+        RuntimeException invokeException = new RuntimeException();
+
+        // 调用
+        notifyService.processNotifyResult(task, invokeResult, invokeException);
+        // 断言
+        PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId());
+        assertNotEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime());
+        assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime());
+        assertEquals(dbTask.getNotifyTimes(), 1);
+        assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.REQUEST_FAILURE.getStatus());
+    }
+
+    @Test
+    public void testGetNotifyTask() {
+        // mock 数据(task)
+        PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class);
+        notifyTaskMapper.insert(task);
+        // 准备参数
+        Long id = task.getId();
+
+        // 调用
+        PayNotifyTaskDO dbTask = notifyService.getNotifyTask(id);
+        // 断言
+        assertPojoEquals(dbTask, task);
+    }
+
+    @Test
+    public void testGetNotifyTaskPage() {
+        // mock 数据
+        PayNotifyTaskDO dbTask = randomPojo(PayNotifyTaskDO.class, o -> { // 等会查询到
+            o.setAppId(1L);
+            o.setType(PayNotifyTypeEnum.REFUND.getType());
+            o.setDataId(100L);
+            o.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus());
+            o.setMerchantOrderId("P110");
+            o.setCreateTime(buildTime(2023, 2, 3));
+        });
+        notifyTaskMapper.insert(dbTask);
+        // 测试 appId 不匹配
+        notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setAppId(2L)));
+        // 测试 type 不匹配
+        notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setType(PayNotifyTypeEnum.ORDER.getType())));
+        // 测试 dataId 不匹配
+        notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setDataId(200L)));
+        // 测试 status 不匹配
+        notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setStatus(PayNotifyStatusEnum.FAILURE.getStatus())));
+        // 测试 merchantOrderId 不匹配
+        notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setMerchantOrderId(randomString())));
+        // 测试 createTime 不匹配
+        notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setCreateTime(buildTime(2023, 1, 1))));
+        // 准备参数
+        PayNotifyTaskPageReqVO reqVO = new PayNotifyTaskPageReqVO();
+        reqVO.setAppId(1L);
+        reqVO.setType(PayNotifyTypeEnum.REFUND.getType());
+        reqVO.setDataId(100L);
+        reqVO.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus());
+        reqVO.setMerchantOrderId("P110");
+        reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+
+        // 调用
+        PageResult<PayNotifyTaskDO> pageResult = notifyService.getNotifyTaskPage(reqVO);
+        // 断言
+        assertEquals(1, pageResult.getTotal());
+        assertEquals(1, pageResult.getList().size());
+        assertPojoEquals(dbTask, pageResult.getList().get(0));
+    }
+
+    @Test
+    public void testGetNotifyLogList() {
+        // mock 数据
+        PayNotifyLogDO dbLog = randomPojo(PayNotifyLogDO.class);
+        notifyLogMapper.insert(dbLog);
+        PayNotifyLogDO dbLog02 = randomPojo(PayNotifyLogDO.class);
+        notifyLogMapper.insert(dbLog02);
+        // 准备参数
+        Long taskId = dbLog.getTaskId();
+
+        // 调用
+        List<PayNotifyLogDO> logList = notifyService.getNotifyLogList(taskId);
+        // 断言
+        assertEquals(logList.size(), 1);
+        assertPojoEquals(dbLog, logList.get(0));
     }
 
     private void mockLock(Long id) {

+ 2 - 1
yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/clean.sql

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

+ 15 - 1
yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/create_tables.sql

@@ -129,4 +129,18 @@ CREATE TABLE IF NOT EXISTS `pay_notify_task` (
     `deleted`            bit(1)        NOT NULL DEFAULT FALSE,
     `tenant_id`           bigint(20)    NOT NULL DEFAULT 0,
     PRIMARY KEY ("id")
-) COMMENT = '支付通知';
+) COMMENT = '支付通知任务';
+
+CREATE TABLE IF NOT EXISTS `pay_notify_log` (
+    "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    `task_id`             bigint(20)    NOT NULL,
+    `notify_times`         int    NOT NULL,
+    `response`         varchar(1024) NOT NULL,
+    `status`             tinyint(4)    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,
+    PRIMARY KEY ("id")
+) COMMENT = '支付通知日志';