NodeJS+TypeScript下BullMQ的Jest可复用Mock创建失败问题
在NodeJS+TypeScript环境中Mock BullMQ时遇到"TypeError: bullmq_1.Queue is not a constructor"错误
问题背景
我需要验证初始化流程的逻辑:实例化3个Queue、每个Queue添加1个任务、启动对应Worker。源码通过import {Queue} from 'bullmq';引入,用new Queue(...)创建实例,调用newQueue.add(...)添加任务。按照Jest文档和相关方案在__mocks__目录编写可复用Mock,但执行测试时抛出**"TypeError: bullmq_1.Queue is not a constructor"**错误。
之前尝试的Mock代码
第一段Mock:
const mockAdd = jest.fn(() => console.log('test')); const mockQueue = jest.fn(function () { return { add: mockAdd, }; }); const mockBullmq = jest.fn(function () { return { Queue: mockQueue, }; }); export { mockAdd, mockQueue, mockBullmq as default};
第二段Mock:
const mockAdd = jest.fn(() => console.log('test')); const mockQueue = jest.fn(function () { return { add: mockAdd, }; }); const mockBullmq = jest.mock('./bullmq', function () { return { Queue: mockQueue, }; }); export { mockAdd, mockQueue, mockBullmq as default};
原测试用例
import queue from '@worker/queue'; import { Queue, Worker, add } from '@mocks/bullmq'; describe('Test queue setup:', () => { it('should connect to queues', async () => { await queue.setup(); expect(Queue).toHaveBeenCalledTimes(3); expect(Queue.mock.instances).toHaveLength(3); expect(add).toHaveBeenCalledTimes(3); expect(Queue.mock.instances[0].add).toHaveBeenCalledTimes(1); expect(Worker).toHaveBeenCalledTimes(3); }); });
错误原因
- Mock模块结构错误:第一段Mock把
mockBullmq写成返回对象的函数,源码import {Queue} from 'bullmq'拿到的是这个函数,而非函数返回的Queue构造函数,导致无法new实例。 - 误用
jest.mock():第二段Mock在__mocks__模块内部调用jest.mock(),这个函数应该在测试用例中触发Mock,而非Mock模块里。 - 导入方式错误:测试用例直接从
@mocks/bullmq导入,Jest需要自动替换真实模块,应该从真实的bullmq包导入Mock后的对象。
正确解决方案
1. 编写正确的__mocks__/bullmq.ts
// Mock Queue的add方法,返回模拟的任务结果 export const mockAdd = jest.fn().mockResolvedValue({ id: 'mock-job-id' }); // 定义Queue的Mock构造函数,返回包含add方法的实例 export const MockQueue = jest.fn(() => ({ add: mockAdd, // 若源码用到Queue的其他方法,比如close,可在此补充:close: jest.fn() })); // 定义Worker的Mock构造函数,根据源码用到的方法补充 export const MockWorker = jest.fn(() => ({ start: jest.fn().mockResolvedValue(true), })); // 导出与真实bullmq一致的模块结构,适配默认导入 export default { Queue: MockQueue, Worker: MockWorker, }; // 单独导出Queue和Worker,适配命名导入 export const Queue = MockQueue; export const Worker = MockWorker;
2. 修正测试用例
import queue from '@worker/queue'; // 从真实的bullmq导入,Jest会自动替换为__mocks__中的实现 import { Queue, Worker, mockAdd } from 'bullmq'; describe('Test queue setup:', () => { // 每次测试前清空Mock调用记录,避免测试污染 beforeEach(() => { jest.clearAllMocks(); }); it('should initialize queues, add jobs and start workers', async () => { await queue.setup(); // 验证Queue被实例化3次 expect(Queue).toHaveBeenCalledTimes(3); expect(Queue.mock.instances).toHaveLength(3); // 验证所有Queue实例的add方法总共被调用3次 expect(mockAdd).toHaveBeenCalledTimes(3); // 验证Worker被实例化3次 expect(Worker).toHaveBeenCalledTimes(3); }); });
关键注意事项
- 确保
__mocks__目录放在项目根目录(针对node_modules里的bullmq包),Jest会自动识别同名模块进行替换。 - 若需要强制启用Mock,可在测试用例顶部添加
jest.mock('bullmq');,通常Jest会自动处理。 - TypeScript环境下,若出现类型报错,可通过
typeof继承真实模块类型,比如:type QueueInstance = InstanceType<typeof import('bullmq').Queue>;,再让Mock实例匹配该类型。
内容的提问来源于stack exchange,提问作者user9839468
相关产品推荐
相关产品推荐

