如何在Jest中Mock node-cron定时任务?
解决Node.js TypeScript应用中node-cron的Jest Mock问题
问题根源
- jest.mock调用位置错误:Jest会自动将
jest.mock语句提升到模块最顶部执行,你把它放在beforeEach里,导致导入的Cron是原始模块而非mock版本,所以Cron.schedule不是jest mock函数,自然没有mockImplementationOnce方法。 - 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
相关产品推荐
相关产品推荐

