You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jasmine/Jest中对唯一方法调用进行单元测试?

实现方案

你需要先把被测的foo函数替换为Jasmine/Jest的Mock函数,之后通过统计指定参数的匹配调用次数来实现断言,不需要依赖原生的toHaveBeenCalledOnceWith匹配器。

基础通用实现(兼容Jasmine和Jest)

直接过滤Mock的调用记录,匹配目标参数后断言次数为1即可:

// 示例:断言 foo 传入参数 (1, "test", {id: 2}) 的调用仅出现1次
const targetArgs = [1, "test", {id: 2}];
// 筛选出参数匹配的调用次数
// Jasmine 环境写法
const matchCount = foo.calls.allArgs().filter(args => jasmine.matchersUtil.equals(args, targetArgs)).length;
// Jest 环境写法,替换上面一行即可
// const matchCount = foo.mock.calls.filter(args => expect.equals(args, targetArgs)).length;

expect(matchCount).toBe(1);

上述写法直接用框架内置的深比较逻辑,支持识别expect.any(Number)这类非对称匹配器参数,不需要自己写参数判断逻辑。

进阶:封装为自定义匹配器

如果需要多次使用该逻辑,可以封装为自定义匹配器简化调用,以Jest为例:

// 放在jest.setup.js中全局注册,或单测文件顶部局部注册
expect.extend({
  toHaveBeenCalledNTimesWith(mockFn, expectedTimes, ...expectedArgs) {
    if (!mockFn.mock) {
      return {
        pass: false,
        message: () => `传入的参数不是合法的Mock函数`
      }
    }
    const matchedCount = mockFn.mock.calls.filter(call => this.equals(call, expectedArgs)).length;
    const pass = matchedCount === expectedTimes;
    return {
      pass,
      message: () => pass 
        ? `预期${mockFn.getMockName()}调用${expectedArgs}的次数不等于${expectedTimes},实际为${matchedCount}`
        : `预期${mockFn.getMockName()}调用${expectedArgs}的次数为${expectedTimes},实际为${matchedCount}`
    }
  }
})

// 测试中直接调用即可
// 断言 foo 调用参数为 1, "test" 的次数为1
expect(foo).toHaveBeenCalledNTimesWith(1, 1, "test");
// 也可以复用匹配其他次数,比如断言参数为 2 的调用出现过2次
expect(foo).toHaveBeenCalledNTimesWith(2, 2);

内容的提问来源于stack exchange,提问作者danchez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 20:06:00