使用 NestJS 和异步函数开玩笑

Jest with NestJS and async function

我正在尝试在 nestJS.

中测试 service 的异步函数

这个函数是异步的...基本上从数据库中获取一个值(JSON)(使用存储库 - TypeORM),当成功获取数据时,“转换”到不同的 class (DTO)... 实施:

async getAppConfig(): Promise<ConfigAppDto> {
  return this.configRepository.findOne({
    key: Equal("APPLICATION"),
  }).then(config => {
    if (config == null) {
      return new class implements ConfigAppDto {
        clientId = '';
        clientSecret = '';
      };
    }
    return JSON.parse(config.value) as ConfigAppDto;
  });
}

使用控制器,我检查了它是否工作正常。 现在,我正在尝试使用 Jest 进行测试,但没有成功...... 我的问题是如何从 repository..

模拟 findOne 函数

编辑:我正在尝试使用 @golevelup/nestjs-testing 来模拟 Repository!

我已经嘲笑了 repository,但由于某些原因,resolve 从未被调用过..

describe('getAppConfig', () => {
  const repo = createMock<Repository<Config>>();

  beforeEach(async () => {
    await Test.createTestingModule({
      providers: [
        ConfigService,
        {
          provide: getRepositoryToken(Config),
          useValue: repo,
        }
      ],
    }).compile();
  });

  it('should return ConfigApp parameters', async () => {
    const mockedConfig = new Config('APPLICATION', '{"clientId": "foo","clientSecret": "bar"}');
    repo.findOne.mockResolvedValue(mockedConfig);
    expect(await repo.findOne()).toEqual(mockedConfig); // ok

    const expectedReturn = new class implements ConfigAppDto {
      clientId = 'foo';
      clientSecret = 'bar';
    };
    expect(await service.getAppConfig()).toEqual(expectedReturn);

    // jest documentation about async -> https://jestjs.io/docs/en/asynchronous
    // return expect(service.getAppConfig()).resolves.toBe(expectedReturn);
  });
})

使用调试,我看到调用了 service.getAppConfig(),也调用了 repository.findOne(),但是从未调用过 findOne 存储库的 .then

Update:我正在尝试使用 @golevelup/nestjs-testing 模拟存储库,但出于某种原因,模拟结果在服务上不起作用。 如果我仅使用 jest 模拟存储库(如下面的代码),则测试有效...所以,我认为我真正的问题是 @golevelup/nestjs-testing.

...
provide: getRepositoryToken(Config),
useValue: {
  find: jest.fn().mockResolvedValue([new Config()])
},
...

我认为 expect(await repo.findOne()).toEqual(mockedConfig); 有效是因为你嘲笑了它,所以它立即 returns。 在 expect(await service.getAppConfig()).toEqual(expectedReturn); 的情况下,您没有模拟它,因此它可能需要更多时间,因此 Promise 之前的 it 函数 returns 完全解析。

如果您模拟对 getAppConfig().

的调用,您从 jest 文档中发布的评论应该可以解决问题
service.getAppConfig = jest.fn(() => Promise.resolve(someFakeValue))

spyOn(service, 'getAppConfig').and.mockReturnValue(Promise.resolve(fakeValue))

所以,我真正的问题是我如何在 NestJS 上嘲笑 Repository。 出于某种原因,当我使用 @golevelup/nestjs-testing 进行模拟时,奇怪的事情发生了!

我真的没有在 @golevelup/nestjs-testing 上找到关于这个的好的文档,所以,我放弃了使用它。

我对该问题的解决方案是仅使用 JestNestJS 函数...结果代码为:

服务:

// i'm injecting Connection because I need for some transactions later;
constructor(@InjectRepository(Config) private readonly configRepo: Repository<Config>, private connection: Connection) {}

async getAppConfig(): Promise<ConfigApp> {
  return this.configRepo.findOne({
    key: Equal("APPLICATION"),
  }).then(config => {
    if (config == null) {
      return new ConfigApp();
    }
    return JSON.parse(config.value) as ConfigApp;
  })
}

测试:

describe('getAppConfig', () => {
  const configApi = new Config();
  configApi.key = 'APPLICATION';
  configApi.value = '{"clientId": "foo", "clientSecret": "bar"}';

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        ConfigAppService,
        {
          provide: getRepositoryToken(Config),
          useValue: {
            findOne: jest.fn().mockResolvedValue(new
            Config("APPLICATION", '{"clientId": "foo", "clientSecret": "bar"}')),
          },
        },
        {
          provide: getConnectionToken(),
          useValue: {},
        }
      ],
    }).compile();

    service = module.get<ConfigAppService>(ConfigAppService);
  });

  it('should return ConfigApp parameters', async () => {
    const expectedValue: ConfigApp = new ConfigApp("foo", "bar");

    return service.getAppConfig().then(value => {
      expect(value).toEqual(expectedValue);
    })
  });
})

此解决方案使用的一些来源: https://github.com/jmcdo29/testing-nestjs/tree/master/apps/typeorm-sample

from @roberto-correia 让我想知道我们使用包 @golevelup/nestjs-testing.

中的 createMock 的方式是否一定有问题

原来方法超过执行时间的原因与createMock没有实现mocking有关,没有return任何东西,除非被告知去做所以。

为了使该方法起作用,我们必须让模拟方法在测试开始时解决一些问题:

usersRepository.findOneOrFail.mockResolvedValue({ userId: 1, email: "some-random-email@email.com" });

一个基本的工作解决方案:

describe("UsersService", () => {
  let usersService: UsersService;
  const usersRepository = createMock<Repository<User>>();

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UsersService,
        {
          provide: getRepositoryToken(User),
          useValue: usersRepository,
        },
    }).compile();

    usersService = module.get(UsersService);
  });

  it("should be defined", () => {
    expect(usersService).toBeDefined();
  });
  it("finds a user", async () => {
    usersRepository.findOne.mockResolvedValue({ userId: 1, email: "some-random-email@email.com" });

    expect(await usersRepository.findOne()).toBe({ userId: 1, email: "some-random-email@email.com" });
  });
});