You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jest中Mock node-cron定时任务?

解决Node.js TypeScript应用中node-cron的Jest Mock问题

问题根源

  1. jest.mock调用位置错误:Jest会自动将jest.mock语句提升到模块最顶部执行,你把它放在beforeEach里,导致导入的Cron是原始模块而非mock版本,所以Cron.schedule不是jest mock函数,自然没有mockImplementationOnce方法。
  2. Mock结构不完整:业务代码中调用了this.cronJob.destroy(),但你当前的mock没有给schedule返回的对象添加destroy方法,后续测试还会出现新错误。

修正后的测试代码

import * as Cron from 'node-cron';
import { SubscriberRetryCronLoader } from '../../../src/Crons/subscriberRetryCronLoader';
import { LogMock } from '../mocks';
import { getSubscriberByStatus, SubscriberStatus } from '../../../src/lib/utils';

// 提前mock node-cron,Jest会自动将该语句提升到模块顶部
jest.mock('node-cron', () => ({
  schedule: jest.fn(() => ({
    // 模拟destroy方法,匹配业务代码中的调用逻辑
    destroy: jest.fn()
  }))
}));

// Mock业务依赖的getSubscriberByStatus,避免测试依赖外部逻辑
jest.mock('../../../src/lib/utils', () => ({
  ...jest.requireActual('../../../src/lib/utils'),
  getSubscriberByStatus: jest.fn()
}));

describe('Retry cron loader', () => {
    let subscriberRetryCronLoader: SubscriberRetryCronLoader;
    let mockLog: LogMock;

    beforeEach(() => {
        jest.clearAllMocks();
        mockLog = new LogMock();
        subscriberRetryCronLoader = new SubscriberRetryCronLoader(mockLog);
    });

    it('should start cron process and run retryBrokenSubscribers', async () => {
        // 模拟getSubscriberByStatus返回空数组
        (getSubscriberByStatus as jest.Mock).mockResolvedValue([]);
        
        await subscriberRetryCronLoader.startCronProcess();

        // 断言cron调度被正确触发
        expect(Cron.schedule).toHaveBeenCalledWith(
            '* * * * *',
            expect.any(Function)
        );
        // 断言重试逻辑被执行
        expect(getSubscriberByStatus).toHaveBeenCalledWith(SubscriberStatus.CircuitBroken);
        expect(mockLog.info).toHaveBeenCalledWith('No of broken subscribers found retry cron loader: 0');
    });

    it('should destroy cron job correctly', () => {
        subscriberRetryCronLoader.cronJob = { destroy: jest.fn() };
        subscriberRetryCronLoader.destroyCronJob();
        expect(subscriberRetryCronLoader.cronJob.destroy).toHaveBeenCalled();
    });
});

关键说明

  • jest.mock的位置:必须放在模块顶部,确保导入的Cron是mock后的版本。
  • 完整的Mock对象:schedule返回的对象需要包含destroy方法,和业务代码的调用逻辑匹配。
  • Mock依赖函数:getSubscriberByStatus是业务代码中的外部依赖,mock它的返回值可以让测试聚焦在SubscriberRetryCronLoader本身的逻辑上。

内容的提问来源于stack exchange,提问作者Sweta Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 17:50:28