Javascript Jest:模拟条件函数调用

Javascript Jest:模拟条件函数调用,javascript,error-handling,jestjs,Javascript,Error Handling,Jestjs,我正在尝试编写一个测试,以确保在适当的时候,使用特定的消息调用特定的函数(在本例中为sentry函数)。然而,当我编写这个测试时,它失败了,我得到以下消息。如何正确模拟handleError.test.js中的captureMessage函数,以确保使用中的字符串handleError.js正确调用该函数?谢谢 错误消息: import {captureMessage} from '@sentry/browser'; const handleError = (error) => {

我正在尝试编写一个测试,以确保在适当的时候,使用特定的消息调用特定的函数(在本例中为sentry函数)。然而,当我编写这个测试时,它失败了,我得到以下消息。如何正确模拟
handleError.test.js
中的
captureMessage
函数,以确保使用
中的
字符串
handleError.js
正确调用该函数?谢谢

错误消息:

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

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

export default handleError;
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.');
});
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.');
});
错误:expect(jest.fn())[.not].toHaveBeenCalledWith()

jest.fn()值必须是模拟函数或间谍。收到:功能: [函数捕获消息]

handleError.js:

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

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

export default handleError;
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.');
});
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.');
});
handleError.test.js:

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

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

export default handleError;
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.');
});
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.');
});

正如@balzee所提到的,您必须实际监视您想要断言的方法。这导致Jest用一个特殊的spy函数来替换该方法,该函数跟踪调用该方法的参数、调用次数等

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

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

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

因此,最终测试应该是:

handleError.test.js:

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

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

export default handleError;
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.');
});
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.');
});

但是,当我编写此测试时,它失败了,我得到了以下消息。
我可能误解了,但我认为您忘记了添加消息。此外,当类中定义了error.name时,您可以在条件内部调用的其他函数上使用。您还可以使用
jest.spy()
监视
captureMessage
方法,然后测试是否使用参数调用该方法。现在你还没有在测试其ArgumentsHanks@TomM的方法上对存根进行监视,对不起,忘记了错误消息,它现在就在那里!