如何在NestJS测试中mock createQueryBuilder方法?
NestJS 服务方法
getAllTests 测试问题修正 问题根源
你的测试代码存在两个核心问题:
- 查询构建器实例不匹配:
createQueryBuilder的 mock 每次调用都会返回全新的对象,你提前获取的qb和服务实际执行时生成的查询构建器不是同一个实例,导致 mock 的方法无法生效。 - 错误 mock 未作用到目标实例:在测试
where/getMany抛出错误时,你 spyOn 的是某次调用返回的旧实例方法,但服务执行时会生成新的查询构建器实例,所以错误逻辑没有被触发。
修正后的测试代码
let service: TestService; let repo: Repository<TestEntity>; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ TestService, { provide: getRepositoryToken(TestEntity), useValue: { create: jest.fn(), save: jest.fn(), delete: jest.fn(), createQueryBuilder: jest.fn(() => ({ where: jest.fn().mockReturnThis(), getMany: jest.fn(), getOne: jest.fn(), })), }, }, ], }).compile(); service = module.get<TestService>(TestService); repo = module.get<Repository<TestEntity>>(getRepositoryToken(TestEntity)); }); describe('getAllTests()', () => { it('should successfully return a list of tests', async () => { const mockTests: TestEntity[] = []; // 重新mock createQueryBuilder,确保服务用到的实例带有指定的getMany返回值 jest.spyOn(repo, 'createQueryBuilder').mockReturnValue({ where: jest.fn().mockReturnThis(), getMany: jest.fn().mockResolvedValue(mockTests), } as any); const result = await service.getAllTests('foo'); expect(result).toEqual(mockTests); // 验证调用参数是否正确 expect(repo.createQueryBuilder).toHaveBeenCalledWith('test'); // 替换为你的实际tableName expect(repo.createQueryBuilder().where).toHaveBeenCalledWith({ organization: 'foo' }); }); it('should throw an error when createQueryBuilder() fails', async () => { jest.spyOn(repo, 'createQueryBuilder').mockImplementation(() => { throw new Error(); }); await expect(service.getAllTests('foo')).rejects.toThrow(InternalServerErrorException); }); it('should throw an error when createQueryBuilder().where fails', async () => { jest.spyOn(repo, 'createQueryBuilder').mockReturnValue({ where: jest.fn().mockImplementation(() => { throw new Error(); }), getMany: jest.fn(), } as any); await expect(service.getAllTests('foo')).rejects.toThrow(InternalServerErrorException); }); it('should throw an error when createQueryBuilder().getMany fails', async () => { jest.spyOn(repo, 'createQueryBuilder').mockReturnValue({ where: jest.fn().mockReturnThis(), getMany: jest.fn().mockImplementation(() => { throw new Error(); }), } as any); await expect(service.getAllTests('foo')).rejects.toThrow(InternalServerErrorException); }); });
关键修正点
- 精准控制查询构建器实例:在需要自定义返回值或错误逻辑时,重新 mock
createQueryBuilder,让它返回预先定义好方法行为的实例,确保服务执行时用到的是这个 mock 实例。 - 简化异步错误断言:异步函数的错误断言不需要包装成箭头函数,直接用
await expect(service.getAllTests('foo')).rejects.toThrow(...)即可。 - 添加调用验证:通过
toHaveBeenCalledWith验证方法的调用参数是否符合预期,提升测试的严谨性。
内容的提问来源于stack exchange,提问作者Chris Barr
相关产品推荐
相关产品推荐

