笑话:模拟条件函数调用

Jim*_*mmy 2 javascript error-handling jestjs

我正在尝试编写一个测试,以确保在适当的情况下,使用特定消息调用特定函数(在本例中为哨兵函数)。但是,当我编写此测试时,它失败了,并且收到以下消息。如何正确模拟captureMessagein 函数handleError.test.js以确保使用"this is an error message."in 字符串正确调用它handleError.js?谢谢!

错误信息:

错误:expect(jest.fn())[.not].toHaveBeenCalledWith()

jest.fn() 值必须是模拟函数或间谍。收到:函数:[函数captureMessage]

处理错误.js:

import {captureMessage} from '@sentry/browser';

const handleError = (error) => {
  if (error.name === "ApiError") {
    captureMessage('this is an error message.');
  }
};

export default handleError;
Run Code Online (Sandbox Code Playgroud)

处理错误.test.js:

import {captureMessage} from '@sentry/browser';
import handleError from '../handleError';

class ApiError extends Error {
  constructor() {
    super();
    this.name = 'ApiError';
  }
}

test('When an ApiError is returned with no action type, sentry is notified', () => {
  const sampleError = new ApiError();
  handleError(sampleError);
  expect(captureMessage).toHaveBeenCalledWith('this is an error message.');
});
Run Code Online (Sandbox Code Playgroud)

Gre*_*egL 5

正如@balzee 提到的,你必须真正监视你想要断言的方法。这导致 Jest 用一个特殊的间谍函数替换该方法,该函数跟踪调用它的参数、调用它的次数等等。

您还应该为该函数提供一个模拟实现,以便在运行单元测试时实际上不会调用 Sentry。

最后,当监视一个方法时,首先传递该方法所在的对象,然后以字符串形式传递该方法的名称。然后,Jest 用间谍函数替换对象上的该属性,如果没有给出模拟实现,该函数将调用原始函数。

如果不引用函数所在的对象,您只需更改局部函数变量指向的内容,从原始/真实函数更改为玩笑间谍函数。这不会改变您正在测试的代码调用的函数,因此测试将失败。

所以最终的测试应该是:

处理错误.test.js:

import * as sentry from '@sentry/browser'; // CHANGED
import handleError from '../handleError';

class ApiError extends Error {
  constructor() {
    super();
    this.name = 'ApiError';
  }
}

// added this to remove any spies/mocks after the test
afterEach(() => {
  jest.restoreAllMocks();
});

test('When an ApiError is returned with no action type, sentry is notified', () => {
  const sampleError = new ApiError();
  // added next line
  jest.spyOn(sentry, 'captureMessage').mockImplementation(() => {});
  handleError(sampleError);
  // note the use of `sentry.captureMessage`, which is now a jest spy fn
  expect(sentry.captureMessage).toHaveBeenCalledWith('this is an error message.');
});
Run Code Online (Sandbox Code Playgroud)