如何检查多次调用开玩笑间谍的多个参数?

How to check multiple arguments on multiple calls for jest spies?

我在 React 组件中有以下功能:

onUploadStart(file, xhr, formData) {
  formData.append('filename', file.name);
  formData.append('mimeType', file.type);
}

这是我的测试,至少可以调用间谍:

const formData = { append: jest.fn() };
const file = { name: 'someFileName', type: 'someMimeType' };
eventHandlers.onUploadStart(file, null, formData);

expect(formData.append).toHaveBeenCalledWith(
  ['mimeType', 'someMimeType'],
  ['fileName', 'someFileName']
);

但是,断言无效:

Expected mock function to have been called with:
 [["mimeType", "someMimeType"], ["fileName", "someFileName"]]
But it was called with:
  ["mimeType", "someMimeType"], ["filename", "someFileName"]

正确的使用方法是什么toHaveBeenCalledWith

签名是 .toHaveBeenCalledWith(arg1, arg2, ...),其中 arg1, arg2, ... 表示在 单个 调用中 (see)。

如果您想测试多个调用,只需 expect 多次。

遗憾的是,我还没有找到测试多次调用顺序的方法。

我能够模拟多个调用并以这种方式检查参数:

expect(mockFn.mock.calls).toEqual([
  [arg1, arg2, ...], // First call
  [arg1, arg2, ...]  // Second call
]);

其中 mockFn 是您模拟的函数名称。

这对我也有用...初始页面加载进行默认搜索...用户交互和点击搜索进行另一次搜索...需要验证搜索过程是否正确增加了搜索值...

let model = {
        addressLine1: null,
        addressLine2: null,
        city: null,
        country: "US"};
let caModel = { ...model, country: "CA" };
const searchSpy = props.patientActions.searchPatient;
expect(searchSpy.mock.calls).toEqual([[{ ...model }], [{ ...caModel }]]);

自 jest 23.0 以来有 .toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....) https://jestjs.io/docs/expect#tohavebeennthcalledwithnthcall-arg1-arg2-

Also under the alias: .nthCalledWith(nthCall, arg1, arg2, ...)

If you have a mock function, you can use .toHaveBeenNthCalledWith to test what arguments it was nth called with. For example, let's say you have a drinkEach(drink, Array<flavor>) function that applies f to a bunch of flavors, and you want to ensure that when you call it, the first flavor it operates on is 'lemon' and the second one is 'octopus'. You can write:

test('drinkEach drinks each drink', () => {
  const drink = jest.fn();
  drinkEach(drink, ['lemon', 'octopus']);
  expect(drink).toHaveBeenNthCalledWith(1, 'lemon');
  expect(drink).toHaveBeenNthCalledWith(2, 'octopus');
});

Note: the nth argument must be positive integer starting from 1.

您还可以测试 toHaveBeenCalledWith 并针对每个预期参数组合测试多次。

一个示例是 Google Analytics plugin api 使用具有不同参数组合的相同函数调用。

function requireGoogleAnalyticsPlugins() {
  ...
  ga('create', 'UA-XXXXX-Y', 'auto');
  ga('require', 'localHitSender', {path: '/log', debug: true});
  ga('send', 'pageview');
}

为了对此进行测试,下面的示例测试了 GA 已使用各种参数组合被调用了三次。

describe("requireGoogleAnalyticsPlugins", () => {
  it("requires plugins", () => {
    requireGoogleAnalyticsPlugins();
    expect(GoogleAnalytics.ga.toHaveBeenCalledTimes(3);
    expect(GoogleAnalytics.ga).toHaveBeenCalledWith('create', 'UA-XXXXX-Y', 'auto');
    expect(GoogleAnalytics.ga).toHaveBeenCalledWith('require', 'localHitSender', {path: '/log', debug: true});
    expect(GoogleAnalytics.ga).toHaveBeenCalledWith('send', 'pageview');
  });
});

在 OP 案例中,您可以使用

进行测试
expect(formData.append).toHaveBeenCalledWith('mimeType', 'someMimeType');
expect(formData.append).toHaveBeenCalledWith('fileName', 'someFileName');

基于 Andi 的另一种解决方案。 Select 您想要的调用并检查参数的值。在此示例中,选择了第一个调用:

expect(mockFn.mock.calls[0][0]).toEqual('first argument');
expect(mockFn.mock.calls[0][1]).toEqual('second argument');

我建议查看这个 Jest 备忘单:

https://devhints.io/jest

您还可以为每次调用创建一个预期参数数组并对其进行循环:

const expectedArgs = ['a', 'b', 'c', 'd']
expectedArgs.forEach((arg, index) => 
    expect(myFunc).toHaveBeenNthCalledWith(index + 1, arg))

这个解决方案考虑了调用的顺序。如果您不关心顺序,可以使用不带索引的 toHaveBeenCalledWith

要重置模拟的计数,您可以调用 jest.clearAllMocks

这在 beforeEach 测试之间最有用。

beforeEach(() => jest.clearAllMocks());

您可以在您的间谍上使用 .calls returns 一个 Calls 接口,其中包括以下方法:

/** will return the arguments passed to call number index **/
argsFor(index: number): any[];

那么您可以执行以下操作:

const formData = { append: jest.fn() };
const file = { name: 'someFileName', type: 'someMimeType' };
eventHandlers.onUploadStart(file, null, formData);

expect(formData.append).toHaveBeenCalledTimes(2);
expect(formData.append.argsFor(0)).toEqual(
  ['fileName', 'someFileName']
);
expect(formData.append.argsFor(1)).toEqual(
  ['mimeType', 'someMimeType'],
);