【问题标题】:如何在 Jest 中正确地让 mock 抛出错误?
【发布时间】:2018-09-24 21:24:14
【问题描述】:

我正在使用 Jest 测试我的 GraphQL api。

我为每个查询/变异使用单独的测试套件

我有 2 个测试(每个测试都在一个单独的测试服中),其中我模拟了一个用于突变的函数(即 Meteor 的 callMethod)。

  it('should throw error if email not found', async () => {
    callMethod
      .mockReturnValue(new Error('User not found [403]'))
      .mockName('callMethod');

    const query = FORGOT_PASSWORD_MUTATION;
    const params = { email: 'user@example.com' };

    const result = await simulateQuery({ query, params });

    console.log(result);

    // test logic
    expect(callMethod).toBeCalledWith({}, 'forgotPassword', {
      email: 'user@example.com',
    });

    // test resolvers
  });

当我console.log(result) 我得到

{ data: { forgotPassword: true } }

这种行为不是我想要的,因为在.mockReturnValue 我抛出了一个错误,因此期望result 有一个错误对象

然而,在这个测试之前,另一个是运行

 it('should throw an error if wrong credentials were provided', async () => {
    callMethod
      .mockReturnValue(new Error('cannot login'))
      .mockName('callMethod');

而且它工作正常,错误被抛出

我想问题是测试完成后模拟没有被重置。 在我的jest.conf.js 我有clearMocks: true

每个测试套件都在一个单独的文件中,我在这样的测试之前模拟函数:

import simulateQuery from '../../../helpers/simulate-query';

import callMethod from '../../../../imports/api/users/functions/auth/helpers/call-accounts-method';

import LOGIN_WITH_PASSWORD_MUTATION from './mutations/login-with-password';

jest.mock(
  '../../../../imports/api/users/functions/auth/helpers/call-accounts-method'
);

describe('loginWithPassword mutation', function() {
...

更新

当我将 .mockReturnValue 替换为 .mockImplementation 时,一切都按预期进行:

callMethod.mockImplementation(() => {
  throw new Error('User not found');
});

但这并不能解释为什么在另一个测试中 .mockReturnValue 工作正常...

【问题讨论】:

  • 看起来你的模拟是返回一个错误对象,而不是抛出它。在没有看到您正在测试的代码的情况下,我只能分享我的经验。我忘记模拟在我的突变中调用的函数,这导致无意中抛出错误。也许你也遇到过类似的事情?

标签: javascript meteor graphql jestjs


【解决方案1】:

对于承诺,可以使用https://jestjs.io/docs/mock-function-api#mockfnmockrejectedvaluevalue

test('async test', async () => {
  const asyncMock = jest.fn().mockRejectedValue(new Error('Async error'));

  await asyncMock(); // throws "Async error"
});

为了测试是否抛出错误,可以使用https://eloquentcode.com/expect-a-function-to-throw-an-exception-in-jest

const func = () => {
  throw new Error('my error')
}
it('should throw an error', () => {
    expect(func).toThrow()
})

【讨论】:

  • 您还需要在您的期望中尝试并捕获,否则它不会正确断言。如果我遗漏了什么,请您改进您的答案或回复。
  • @MGDeveloper 我们在单元测试和使用 toThrow() (jestjs.io/docs/expect#tothrowerror) 时不需要 try-catch。如果您在测试中尝试这样做,它应该可以工作。也可以在这里测试:codesandbox.io/s/jest-playground-forked-euewe?file=/src/…(虽然沙盒内容是暂时的)。如果这令人困惑,我确实将术语从“处理”编辑为“测试”
【解决方案2】:

.mockReturnValue 更改为.mockImplementation

yourMockInstance.mockImplementation(() => {
  throw new Error();
});

如果这是一个承诺,你也可以 .rejects www.jestjs.io/docs/en/asynchronous#resolves--rejects

【讨论】:

  • 酷。如何处理和make和assert?
【解决方案3】:

对于 Angular + Jest:

import { throwError } from 'rxjs';

yourMockInstance.mockImplementation(() => {
  return throwError(new Error('my error message'));
});

【讨论】:

  • 从技术上讲,这不是纯 JS 意义上的throw。您正在将模拟配置为返回一个 RXJS 可观察对象,该对象会立即发出错误通知。不过,也许方便人们在这里看到。接受的答案肯定会使模拟抛出错误。在所有情况下。
  • 只返回throw Error就足够了:yourMockInstance.mockImplementation(() => throwError('my error message'));
猜你喜欢
  • 1970-01-01
  • 2020-08-29
  • 2019-07-12
  • 2017-10-18
  • 2020-11-21
  • 2019-01-03
  • 2018-09-10
  • 2020-10-01
  • 2017-11-21
相关资源
最近更新 更多