如何根据参数多次Stub Mongoose的find方法并解决参数匹配错误?
问题:使用Sinon模拟Mongoose的find查询时出现参数不匹配错误
我需要模拟两个Mongoose查询:
// 查询1:统计所有用户 const totalUser = User.find().countDocuments().exec() // 查询2:统计上周前的用户 const lastWeekUser = User.find({ createdAt: { $lt: lastWeek }}).countDocuments()
编写的Sinon Stub代码如下:
sinon .stub(User, 'find') .withArgs() .callsFake((): any => { return { countDocuments: sinon.stub().callsFake(() => { return { exec: sinon.stub().returns(newUserCount), } }), } }) .withArgs({ createdAt: { $lt: lastWeek }, }) .callsFake((): any => { return { countDocuments: sinon.stub().callsFake(() => { return { exec: sinon.stub().returns(mockedData.length), } }), } })
运行测试时出现错误:Expected 0 arguments, but got 1.
错误原因
Mongoose的find()方法如果不传任何参数,内部其实会默认传入一个空对象{},而不是完全无参数。你的第一个Stub用withArgs()严格匹配0个参数,导致实际调用User.find()时(传入了空对象)无法匹配到这个Stub,进而触发参数不匹配的错误。
另外第二个查询lastWeekUser的countDocuments()没有调用exec(),但你在Stub里还给它嵌套了exec的Stub,这也是多余的。
修正方案
1. 修正参数匹配逻辑
把无参find()的匹配从withArgs()改成withArgs({}),同时用sinon.match()处理对象参数的匹配(避免因对象引用或动态值导致匹配失败)。
2. 简化Stub结构
不需要嵌套多层callsFake,直接用returns返回对应结构即可:
sinon .stub(User, 'find') // 匹配Mongoose无参find实际传入的空对象 .withArgs({}) .returns({ countDocuments: sinon.stub().returns({ exec: sinon.stub().returns(newUserCount) }) }) // 用sinon.match.deepEqual确保深层对象匹配 .withArgs(sinon.match.deepEqual({ createdAt: { $lt: lastWeek } })) .returns({ countDocuments: sinon.stub().returns(mockedData.length) })
补充说明
- 如果
lastWeek是动态生成的日期对象,sinon.match.deepEqual可以确保深层对象的内容匹配,而不是依赖对象引用一致。 - Sinon完全支持对Mongoose查询的参数进行匹配,只要确保匹配逻辑和实际调用的参数一致即可。
内容的提问来源于stack exchange,提问作者Sinan Bayar
相关产品推荐
相关产品推荐

