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

如何在NestJS测试中mock createQueryBuilder方法?

NestJS 服务方法 getAllTests 测试问题修正

问题根源

你的测试代码存在两个核心问题:

  1. 查询构建器实例不匹配:createQueryBuilder 的 mock 每次调用都会返回全新的对象,你提前获取的 qb 和服务实际执行时生成的查询构建器不是同一个实例,导致 mock 的方法无法生效。
  2. 错误 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 15:00:53