Jest.js 如何在NestJS测试中模拟`QuestQueryBuilder`?

kgqe7b3p  于 11个月前  发布在  Jest
关注(0)|答案(1)|浏览(186)

我有这个NestJS服务方法,我需要测试。

async getAllTests(orgId: string): Promise<Array<TestEntity>> {
  try {
    const query = this.repo.createQueryBuilder(this.tableName);
    query.where({ organization: orgId });
    const tests = await query.getMany();
    return tests;
  } catch (ex) {
    throw new InternalServerErrorException();
  }
}

字符串
我在我的测试文件中有这个,它并没有真正工作,但我认为它至少显示了我试图去的方向。

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 qb = repo.createQueryBuilder();
    jest.spyOn(qb, 'getMany').mockResolvedValue([]);

    const result = service.getAllTests('foo');
    await expect(result).resolves.toEqual([]);
  });

  it('should throw an error when createQueryBuilder() fails', async () => {
    jest.spyOn(repo, 'createQueryBuilder').mockImplementation(() => {
      throw new Error();
    });

    const result = () => service.getAllTests('foo');
    await expect(result).rejects.toThrow(InternalServerErrorException);
  });

  it('should throw an error when createQueryBuilder().where fails', async () => {
    jest.spyOn(repo.createQueryBuilder(), 'where').mockImplementation(() => {
      throw new Error();
    });

    const result = () => service.getAllTests('foo');
    await expect(result).rejects.toThrow(InternalServerErrorException);
  });

  it('should throw an error when createQueryBuilder().getMany fails', async () => {
    jest.spyOn(repo.createQueryBuilder(), 'getMany').mockImplementation(() => {
      throw new Error();
    });

    const result = () => service.getAllTests('foo');
    await expect(result).rejects.toThrow(InternalServerErrorException);
  });
});


如何模拟createQueryBuilder()及其方法的返回值或错误?现在,第一个应该实际返回数据的测试实际上返回了undefined,直接模拟createQueryBuilder()的测试可以工作,但其他测试报告如下:

Received promise resolved instead of rejected
Resolved to value: undefined

vwhgwdsa

vwhgwdsa1#

问题是,每当repo.createQueryBuilder()被调用时,它都会返回该对象的一个新示例。因此,每当Jest监视一个子属性时,当真实的方法被调用时,它将返回一个与被监视的示例不同的示例!
下面是我的解决方案。我创建了一个独立的文件test-helpers.ts,其中包含以下内容:

const mockDeleteSingleton = jest.fn().mockReturnThis();
const mockExecuteSingleton = jest.fn().mockReturnThis();
const mockFromSingleton = jest.fn().mockReturnThis();
const mockGetManySingleton = jest.fn().mockReturnThis();
const mockGetOneSingleton = jest.fn().mockReturnThis();
const mockInnerJoinSingleton = jest.fn().mockReturnThis();
const mockInnerJoinAndSelectSingleton = jest.fn().mockReturnThis();
const mockOrderBySingleton = jest.fn().mockReturnThis();
const mockWhereSingleton = jest.fn().mockReturnThis();

export const mockRepository = {
  create: jest.fn().mockReturnThis(),
  save: jest.fn().mockReturnThis(),
  delete: jest.fn().mockReturnThis(),
  findOne: jest.fn().mockReturnThis(),
  find: jest.fn().mockReturnThis(),
  createQueryBuilder: jest.fn(() => ({
    delete: mockDeleteSingleton,
    execute: mockExecuteSingleton,
    from: mockFromSingleton,
    getMany: mockGetManySingleton,
    getOne: mockGetOneSingleton,
    innerJoin: mockInnerJoinSingleton,
    innerJoinAndSelect: mockInnerJoinAndSelectSingleton,
    orderBy: mockOrderBySingleton,
    where: mockWhereSingleton,
  })),
};

字符串
这将允许在对这些子属性调用spyOn时返回这些子属性的完全相同的示例。
所以现在,在我的实际*.spec.ts文件中,我只是使用这个导入的mockRepository作为我的useValue,现在也会减少代码行!

import { mockRepository } from '../testing-helpers';

beforeEach(async () => {
  const module: TestingModule = await Test.createTestingModule({
    providers: [
      TestService,
      {
        provide: getRepositoryToken(TestEntity),
        useValue: mockRepository,  //<--- use it here
      },
    ],
  }).compile();
  
  service = module.get<TestService>(TestService);
  repo = module.get<Repository<TestEntity>>(getRepositoryToken(TestEntity));
});

相关问题