如何检查多个间谍电话的多个参数?

我在 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的正确方法是什么?

122849 次浏览

该签名是 .toHaveBeenCalledWith(arg1, arg2, ...),其中 arg1, arg2, ...意味着 单身呼叫()。

如果你想测试多个调用,只需要 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 }]]);

因为只有23.0有 .toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....) https://jestjs.io/docs/expect#tohavebeennthcalledwithnthcall-arg1-arg2-

也在别名下: . nthCalledWith (nthCall,arg1,arg2,...)

如果您有一个 mock 函数,您可以使用 .toHaveBeenNthCalledWith来测试使用什么参数来调用它。例如,假设您有一个 drinkEach(drink, Array<flavor>)函数,该函数将 f应用于多种口味,并且您希望确保在调用它时,它操作的第一种口味是 'lemon',第二种口味是 'octopus'。你可以写:

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

注意: nth 参数必须是从1开始的正整数。

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

一个例子是 GoogleAnalyticsAPI 插件使用相同的函数调用和不同的参数组合。

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 的解决方案。选择所需的调用并检查参数的值。在此示例中,选择了第一个调用:

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接口的间谍上使用 .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'],
);

由于发生了大量的同步调用,我遇到了一些调用,顺序可能不同。感谢这篇文章,所以我得到了一个方法来验证这一点,并忽略订单。

expect(mockFn.mock.calls).toMatchObject(expect.arrayContaining(
[
objectContaining(oneOfYourObject)
],
[
objectContaining(oneOfYourObject)
],
[
objectContaining(oneOfYourObject)
]
));