如何使用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
相关产品推荐
相关产品推荐

