如何测试方法是否以指定参数被恰好调用指定次数(如一次)?
实现
toHaveBeenCalledTimesWith断言方法 Jest原生没有直接提供同时检查特定参数调用次数的匹配器,但我们可以通过自定义扩展匹配器来实现需求——统计mock函数以指定参数被调用的次数,并验证是否等于预期的N次(不关心调用顺序)。
实现思路
- 校验目标是否为mock函数,确保后续能获取调用记录
- 从mock函数的
mock.calls中提取所有调用参数 - 用Jest内置的深度比对方法,筛选出和目标参数匹配的调用
- 统计匹配次数,和预期次数做对比,返回断言结果
自定义匹配器代码
在测试文件或Jest全局配置文件(如setupTests.js)中添加以下代码:
expect.extend({ toHaveBeenCalledTimesWith(received, expectedTimes, ...expectedArgs) { // 校验是否为mock函数 if (!received.mock) { return { pass: false, message: () => '必须传入mock函数' }; } // 统计匹配指定参数的调用次数 const matchingCallCount = received.mock.calls.filter(call => { return this.equals(call, expectedArgs); }).length; // 返回断言结果 if (matchingCallCount === expectedTimes) { return { pass: true, message: () => `预期mock函数不会以${this.utils.printExpected(expectedArgs)}被调用${expectedTimes}次,但实际符合` }; } else { return { pass: false, message: () => `预期mock函数以${this.utils.printExpected(expectedArgs)}被调用${expectedTimes}次,但实际被调用了${matchingCallCount}次` }; } } });
使用示例
假设我们有一个mock函数,要验证它以['user1', 25]为参数被调用恰好2次:
test('验证mock函数的特定参数调用次数', () => { const userLogger = jest.fn(); userLogger('user1', 25); userLogger('user2', 30); userLogger('user1', 25); // 验证以['user1',25]调用的次数是否为2 expect(userLogger).toHaveBeenCalledTimesWith(2, 'user1', 25); // 验证以['user2',30]调用的次数是否为1 expect(userLogger).toHaveBeenCalledTimesWith(1, 'user2', 30); });
补充说明
- 匹配器使用
this.equals做深度比对,和Jest原生toHaveBeenCalledWith的参数匹配逻辑完全一致,支持对象、数组等复杂参数的校验 - 如果将匹配器代码放到全局配置文件中,所有测试文件无需重复定义即可直接使用
内容的提问来源于stack exchange,提问作者Mikhail Batcer
相关产品推荐
相关产品推荐

