Sinon Mock函数无法多次调用,报错:匿名Mock已被调用一次
问题分析与解决
核心原因
你遇到的ExpectationError: Anonymous mock already called once错误,本质是Sinon匿名mock的默认期望是单次调用,但async.retry会调用getList两次(第一次抛错触发重试,第二次成功),超出了mock期望的调用次数限制。另外你代码里存在变量名大小写笔误(getLisMock vs GetListMock),这也会导致逻辑异常。
解决方案
1. 修正变量名笔误
先把所有变量名统一,比如都用getListMock:
let getListMock = sinon.mock();
2. 调整mock的调用次数期望
不要直接用calledWith,而是通过exactly(n)或atLeast(n)明确允许多次调用:
// 明确期望getList被调用2次,每次参数都是{data: 'data'} getListMock.calledWith({data: 'data'}).exactly(2);
3. 正确设置mock的调用行为
结合onCall设置每次调用的返回:
getListMock.onCall(0).yields(new Error('error'), null); getListMock.onCall(1).yields(null, {items: [{id: 1}]});
4. 完整测试流程示例
const sinon = require('sinon'); const rewire = require('rewire'); const async = require('async'); const assert = require('assert'); // 引入待测试模块 const someModule = rewire('./your-module-path'); describe('someFunc', () => { it('should retry getList on failure', (done) => { // 创建mock并设置期望 let getListMock = sinon.mock(); getListMock.calledWith({data: 'data'}).exactly(2); // 设置两次调用的行为 getListMock.onCall(0).yields(new Error('error'), null); getListMock.onCall(1).yields(null, {items: [{id: 1}]}); // 用rewire替换getList someModule.__set__('getList', getListMock); // 调用待测试函数 someModule.someFunc({data: 'data'}, (err, result) => { try { // 验证mock期望是否满足 getListMock.verify(); // 断言结果正确 assert.deepEqual(result, {items: [{id: 1}]}); done(); } catch (e) { done(e); } }); }); });
额外说明
如果你不确定具体调用次数,也可以用atLeast(1)来允许至少一次调用,但这里因为async.retry的times:3,最多会调用3次(如果前两次都失败),所以根据你的实际逻辑调整次数即可。
内容的提问来源于stack exchange,提问作者Froggy
相关产品推荐
相关产品推荐

