如何Mock Nest服务依赖?解决CronJob重复创建测试报错
Nest服务单元测试:解决定时任务冲突与依赖Mock问题
一、先解决「CHECKER_JOB已存在」定时任务冲突
测试时重复初始化服务会导致CronJob重复注册,有两种快速解决方式:
方式1:测试前清除已注册的定时任务
在测试的beforeEach钩子中清空定时任务队列:
import { CronJob } from 'cron'; beforeEach(() => { // 停止并移除所有已注册的定时任务 Object.values(CronJob.scheduledJobs).forEach(job => job.stop()); Object.keys(CronJob.scheduledJobs).forEach(key => delete CronJob.scheduledJobs[key]); });
方式2:Mock CronJob类,避免实际注册
直接Mock整个cron模块,让CronJob的实例不执行真实逻辑:
jest.mock('cron', () => { const mockCronJob = { start: jest.fn(), stop: jest.fn() }; return { CronJob: jest.fn(() => mockCronJob) }; });
二、正确Mock所有依赖服务与Repository
针对你的7个服务依赖和1个Repository,提供两种Mock方案:
方案1:手动Mock每个依赖(适合需要自定义Mock行为的场景)
在测试模块中为每个依赖提供Mock实现:
import { Test } from '@nestjs/testing'; import { YourService } from './your.service'; // 导入所有依赖的服务和Repository类 import { DepService1 } from '../dep1/dep1.service'; import { DepService2 } from '../dep2/dep2.service'; // ... 其他5个服务 import { YourRepository } from './your.repository'; describe('YourService', () => { let service: YourService; beforeEach(async () => { const moduleRef = await Test.createTestingModule({ providers: [ YourService, // 为每个服务依赖提供空Mock { provide: DepService1, useValue: jest.fn() }, { provide: DepService2, useValue: jest.fn() }, // ... 其他5个服务同理 // Mock Repository,模拟常用方法 { provide: YourRepository, useValue: { find: jest.fn(), save: jest.fn() } } ], }).compile(); service = moduleRef.get<YourService>(YourService); }); it('should be defined', () => { expect(service).toBeDefined(); }); });
方案2:使用.useMocker批量Mock(解决你之前无效的问题)
如果之前用.useMocker没效果,大概率是没正确匹配依赖的token。正确用法如下:
import { Test } from '@nestjs/testing'; import { YourService } from './your.service'; import { getRepositoryToken } from '@nestjs/typeorm'; // 若用TypeORM的Repository import { YourRepository } from './your.repository'; describe('YourService', () => { let service: YourService; beforeEach(async () => { const moduleRef = await Test.createTestingModule({ providers: [YourService], }) .useMocker(token => { // 单独处理Repository的token(TypeORM的Repository token不是类本身) if (token === getRepositoryToken(YourRepository)) { return { find: jest.fn(), save: jest.fn() }; } // 匹配所有服务类依赖,返回空Mock if (typeof token === 'function') { return jest.fn(); } }) .compile(); service = moduleRef.get<YourService>(YourService); }); it('should be defined', () => { expect(service).toBeDefined(); }); });
如果你的Repository是自定义的(非TypeORM),直接匹配Repository类即可,无需getRepositoryToken。
三、验证Jest配置的快速技巧
若仅需确认Jest配置正常,可添加一个基础测试:
it('should run basic jest test', () => { expect(1 + 1).toBe(2); });
此测试通过则说明Jest配置无问题,后续只需聚焦Nest测试模块的配置。
内容的提问来源于stack exchange,提问作者Kaisin Li
相关产品推荐
相关产品推荐

