如何存根Lambda内部函数并统计调用次数?Sinon报错排查
问题根源
你遇到的报错Attempted to wrap undefined property anotherMethod as function,本质是function_2是handler函数的局部内部函数,外部测试代码根本访问不到这个函数,所以sinon没法对它创建spy。
解决方法
要测试内部函数的调用次数,核心是让测试代码能“碰得到”这些内部函数,下面是几种实用方案:
方案1:把内部函数挂载到handler上暴露出来
修改你的source.js,将内部函数挂载到handler自身,这样外部就能访问:
exports.handler = () =>{ // 把内部函数挂载到handler上 handler.function_1 = function function_1 () { return 'something'; }; handler.function_2 = function function_2 () { // 调用时也要用挂载后的引用 handler.function_1(); return 'something'; }; handler.function_2(); };
对应的测试代码调整为:
const handler = require('./source').handler; const sinon = require('sinon'); describe('testing lambdas', () => { it('should call function_2 once', () => { // 给handler上的function_2创建spy const func2Spy = sinon.spy(handler, 'function_2'); const func1Spy = sinon.spy(handler, 'function_1'); // 执行handler handler(); // 断言调用次数 sinon.assert.calledOnce(func2Spy); sinon.assert.calledOnce(func1Spy); // 记得恢复原函数,避免影响其他测试 func2Spy.restore(); func1Spy.restore(); }); });
方案2:单独导出内部函数(推荐)
如果内部函数逻辑独立,直接把它们单独导出,handler再引用,这种方式代码结构更清晰:
// source.js // 单独导出内部函数 exports.function_1 = () => { return 'something'; }; exports.function_2 = () => { exports.function_1(); return 'something'; }; exports.handler = () => { exports.function_2(); };
测试代码可以直接spy导出的函数:
const { handler, function_1, function_2 } = require('./source'); const sinon = require('sinon'); describe('testing lambdas', () => { it('should call function_2 and function_1 correctly', () => { const func1Spy = sinon.spy(function_1); const func2Spy = sinon.spy(function_2); handler(); sinon.assert.calledOnce(func2Spy); sinon.assert.calledOnce(func1Spy); func1Spy.restore(); func2Spy.restore(); }); });
方案3:临时重写handler(不修改原结构的折中方案)
如果不想改动原handler的结构,可以临时重写handler内部的函数逻辑来统计调用次数,不过这种方式比较hack,尽量少用:
const sinon = require('sinon'); const source = require('./source'); describe('testing lambdas', () => { it('should track internal function calls', () => { let func1CallCount = 0; let func2CallCount = 0; // 保存原handler,测试后恢复 const originalHandler = source.handler; source.handler = () => { function function_1() { func1CallCount++; return 'something'; } function function_2() { func2CallCount++; function_1(); return 'something'; } function_2(); }; source.handler(); // 验证调用次数 expect(func2CallCount).toBe(1); expect(func1CallCount).toBe(1); // 恢复原handler source.handler = originalHandler; }); });
注意点
- 所有spy/stub的函数测试后一定要用
restore()恢复,不然会干扰其他测试用例 - 优先选方案1或2,代码可读性和可维护性更高;方案3只适合临时场景
内容的提问来源于stack exchange,提问作者Makarand
相关产品推荐
相关产品推荐

