spyOn模拟类实例方法无效:如何mock函数内调用的类方法
如何正确Mock operationsFunc中创建的SomeCalculator实例的add方法?
问题背景
你提供的业务代码如下:
class SomeCalculator { add(x,y) { console.log('add method is called') return x + y; } } function operationsFunc(y,x) { console.log(x,y) const calc = new SomeCalculator(); console.log('calc', calc); calc.add(x,y); }
测试时尝试Mock add 方法,但编写的测试代码无法阻止真实方法执行:
describe('operationsFunc()', () => { it('add method ', () => { let calc = new SomeCalculator(); let spyObj = spyOn(calc, 'add').and.stub(); console.log('spyObj', spyObj); operationsFunc(2,2); }) })
执行测试后,控制台仍会输出add method is called,说明真实方法未被拦截。
问题原因
你当前的Spy是创建在手动实例化的calc对象上,但operationsFunc内部会重新new SomeCalculator()生成全新实例,这个新实例和你手动创建的calc完全独立,所以Spy无法作用到它。
解决方法
方法1:Spy On SomeCalculator的原型方法
类的所有实例都会继承原型上的方法,直接Spy类原型的add方法,就能覆盖所有新创建的实例:
describe('operationsFunc()', () => { it('should mock add method correctly', () => { // 拦截类原型上的add方法,替换为stub const spyObj = spyOn(SomeCalculator.prototype, 'add').and.stub(); operationsFunc(2,2); // 验证add方法被正确调用 expect(spyObj).toHaveBeenCalledWith(2, 2); }) })
这种方式简单直接,适合只需要Mock单个方法的场景。
方法2:Mock整个SomeCalculator类的构造函数
如果需要完全控制实例的创建逻辑,可以Mock类的构造函数,让它返回预先设置好Spy的实例:
describe('operationsFunc()', () => { it('should mock add method via mocked class', () => { // 创建带有add方法Spy的mock实例 const mockCalc = jasmine.createSpyObj('SomeCalculator', ['add']); // 让SomeCalculator构造函数返回这个mock实例 spyOn(window, 'SomeCalculator').and.returnValue(mockCalc); operationsFunc(2,2); // 验证构造函数和add方法的调用情况 expect(SomeCalculator).toHaveBeenCalled(); expect(mockCalc.add).toHaveBeenCalledWith(2, 2); }) })
注意:如果代码是模块化环境(如ES模块),SomeCalculator不会挂载在window上,需要根据实际作用域调整Spy的目标(比如Spy模块的导出对象)。
内容的提问来源于stack exchange,提问作者JohnJS
相关产品推荐
相关产品推荐

