1. 完善 PayNotifyServiceImpl 的单元测试

This commit is contained in:
YunaiV 2023-07-24 23:04:38 +08:00
parent 3a1694dea3
commit 7c165fb1f6
5 changed files with 193 additions and 9 deletions

View File

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

View File

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

View File

@ -1,7 +1,11 @@
package cn.iocoder.yudao.module.pay.service.notify; package cn.iocoder.yudao.module.pay.service.notify;
import cn.hutool.extra.spring.SpringUtil; 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.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.notify.PayNotifyTaskDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 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;
@ -20,14 +24,17 @@ import org.redisson.api.RLock;
import org.redisson.api.RedissonClient; import org.redisson.api.RedissonClient;
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 org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.Duration; 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.randomPojo;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
@ -167,7 +174,167 @@ public class PayNotifyServiceTest extends BaseDbUnitTest {
// 调用 // 调用
notifyService.executeNotify0(task); 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) { private void mockLock(Long id) {

View File

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

View File

@ -129,4 +129,18 @@ CREATE TABLE IF NOT EXISTS `pay_notify_task` (
`deleted` bit(1) NOT NULL DEFAULT FALSE, `deleted` bit(1) NOT NULL DEFAULT FALSE,
`tenant_id` bigint(20) NOT NULL DEFAULT 0, `tenant_id` bigint(20) NOT NULL DEFAULT 0,
PRIMARY KEY ("id") 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 = '支付通知日志';