【问题标题】:How to mock a promise rejection with Jest如何用 Jest 模拟拒绝承诺
【发布时间】:2021-04-01 16:18:54
【问题描述】:

我在做什么?

我正在学习有关 Nestjs 的课程,其中有一些单元测试它。我编写了这个测试来检查存储库类中的 signUp 方法。问题是为了触发异常,user.save() 行应该返回一个 promise 拒绝(模拟一些写入 db 的问题)。我尝试了几种方法(见下文),但都没有奏效。

问题

结果是测试成功,但是有一个unhandled Promise rejection。这样,即使我断言not.toThow() 确实如此,它也会以相同的unhandled Promise rejection 成功

(node:10149) UnhandledPromiseRejectionWarning: Error: expect(received).rejects.toThrow()

Received promise resolved instead of rejected
Resolved to value: undefined
(Use `node --trace-warnings ...` to show where the warning was created)

如何让它正确拒绝承诺?

代码

下面是我的测试代码和被测函数。

import { ConflictException } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { AuthCredentialsDto } from './dto/auth-credentials.dto';
import { UserRepository } from './user.repository';

describe('UserRepository', () => {
  let userRepository: UserRepository;

  let authCredentialsDto: AuthCredentialsDto = {
    username: 'usahh',
    password: 'passworD12!@',
  };

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [UserRepository],
    }).compile();

    userRepository = module.get<UserRepository>(UserRepository);
  });

  describe('signUp', () => {
    let save: any;
    beforeEach(() => {
      save = jest.fn();
      userRepository.create = jest.fn().mockReturnValue({ save });
    });

    it('throws a conflict exception if user already exist', () => {
      // My first try:
      // save.mockRejectedValue({
      //   code: '23505',
      // });

      // Then I tried this, with and without async await:
      save.mockImplementation(async () => {
        await Promise.reject({ code: '23505' });
      });
      expect(userRepository.signUp(authCredentialsDto)).rejects.toThrow(
        ConflictException,
      );
    });
  });
});


这里测试的函数是:

@EntityRepository(User)
export class UserRepository extends Repository<User> {
  async signUp(authCredentialsDto: AuthCredentialsDto): Promise<void> {
    const { username, password } = authCredentialsDto;
    const user = this.create();

    user.salt = await bcrypt.genSalt();
    user.username = username;
    user.password = await this.hashPassword(password, user.salt);

    try {
      await user.save();
    } catch (e) {
      if (e.code === '23505') {
        throw new ConflictException('Username already exists');
      } else {
        throw new InternalServerErrorException();
      }
    }
  }
}

【问题讨论】:

    标签: unit-testing promise jestjs nestjs ts-jest


    【解决方案1】:

    这应该是异步测试,但它是同步的,即使有被拒绝的promise也不会失败。

    需要链接expect(...).rejects... 返回的承诺:

    it('throws a conflict exception if user already exist', async () => {
      ...
      await expect(userRepository.signUp(authCredentialsDto)).rejects.toThrow(
        ConflictException,
      );
    });
    

    mockImplementation 没有反复试验的余地。模拟应该返回被拒绝的承诺,mockRejectedValue 会这样做。 mockImplementation(async () =&gt; ...) 写的太长了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-21
      • 2018-11-22
      • 2021-11-04
      • 2020-10-07
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      • 2019-11-25
      相关资源
      最近更新 更多