You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 11:57:08