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

如何使用Sinon stub比对对象类型的函数调用入参?

Sinon Stub 引用类型入参比对方案

问题根因

你的推测是对的:Sinon 默认对withArgs/calledWith的参数做 引用相等校验,只有传入的对象和你写的参数是同一个内存引用时才会匹配,不会自动做对象属性的深比对。另外你贴的测试代码还有三处基础写法错误,也是导致用例运行异常的原因:

  • 执行顺序错误:你先调用了被测函数getUser,之后才给stub配置返回值,stub在被调用时还未加载mock规则,默认返回undefined
  • 异步mock写法错误:Mongoose的findOne是异步方法,返回Promise,stub异步返回值不能用returns,要用resolves
  • 对象断言写法错误:用chai做对象值相等断言时,需要加deep标记,否则默认走引用相等判断,属性完全一致的两个不同对象也会断言失败

可行解决方案

方案1:使用Sinon内置深匹配器(最简便)

Sinon 自v5版本后内置了sinon.match匹配器,支持按对象属性做深匹配,不需要额外引入依赖:

it('Should return user info when query with valid userId', async () => {
  // 先配置stub规则,再调用被测函数
  findOneUserStub
    .withArgs(sinon.match({ _id: 'userId_01' }))
    .resolves({ _id: 'userId_01' }); // 异步返回用resolves,不要用returns

  const response = await getUser('userId_01');
  // 对象值相等断言用deep.equal
  expect(response).to.deep.equal({ _id: 'userId_01' });
})

sinon.match(obj)的匹配逻辑是:只要传入的实参包含obj上的所有属性、且属性值一致,就判定为匹配,不需要对象完全同引用。

方案2:自定义匹配校验逻辑

如果内置匹配规则满足不了复杂校验需求,可以给sinon.match传入自定义校验函数,自行实现参数判断逻辑:

findOneUserStub
  .withArgs(sinon.match((callArg) => {
    // 自定义校验逻辑,返回true代表匹配成功
    return callArg && typeof callArg === 'object' && callArg._id === 'userId_01';
  }))
  .resolves({ _id: 'userId_01' });

方案3:调用完成后做入参断言

如果不需要按入参区分stub的返回值,只是想校验函数被调用时传入的参数是否正确,可以不在withArgs里做匹配,等被测函数执行完成后,单独校验stub的调用入参:

it('Should return user info when query with valid userId', async () => {
  findOneUserStub.resolves({ _id: 'userId_01' });
  const response = await getUser('userId_01');

  // 校验stub是否被预期参数调用
  expect(findOneUserStub.calledWith(sinon.match({ _id: 'userId_01' }))).to.be.true;
  expect(response).to.deep.equal({ _id: 'userId_01' });
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 08:18:17