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

如何用Sinon Stub类中私有成员对象的函数?

解决类A私有B实例方法Stub失败的问题

问题原因

你之前的代码失效的核心原因是:先创建了A实例,再Stub B类的方法。A内部的B实例在你Stub之前就已经初始化完成,Stub类的方法不会影响已经存在的实例。

解决方案

方案1:提前Stub B的原型方法(无需修改原代码)

在创建A实例之前,Stub B类的原型方法,这样后续new出来的B实例都会使用被Stub的方法:

describe("A",()=>{
  it("test someFunction", ()=>{
    // 先Stub B的原型方法
    const stub = sinon.stub(B.prototype, "someOtherFunction").resolves();
    // 再创建A实例,此时内部的B实例会使用Stub后的方法
    const a = new A();
    const result = a.someFunction();
    
    // 断言结果与调用情况
    expect(result).to.equal(42);
    expect(stub.calledOnce).to.be.true;
    
    // 测试完成后恢复原方法,避免影响其他测试
    stub.restore();
  })
})

方案2:依赖注入重构(推荐,提升代码可测试性)

修改A类的构造函数,允许外部传入B实例,这样测试时可以直接传入Stub好的B实例,无需依赖内部实现:

重构后的A类

class A{
  private b:B;
  // 构造函数注入B实例,默认值保留原有逻辑
  constructor(bInstance: B = new B()){
    this.b = bInstance;
  }
  
  someFunction(){
    this.b.someOtherFunction();
    return 42;
  }
}

测试代码

describe("A",()=>{
  it("test someFunction", ()=>{
    // 创建B的Stub实例
    const bStub = sinon.createStubInstance(B);
    bStub.someOtherFunction.resolves();
    
    // 传入Stub实例创建A
    const a = new A(bStub);
    const result = a.someFunction();
    
    expect(result).to.equal(42);
    expect(bStub.someOtherFunction.calledOnce).to.be.true;
  })
})

方案3:绕过私有成员(不推荐,破坏封装)

通过类型断言绕过TypeScript的私有成员限制,直接获取A内部的B实例并Stub。这种方法依赖代码的私有实现,后续重构容易导致测试失效:

describe("A",()=>{
  it("test someFunction", ()=>{
    const a = new A();
    // 绕过私有成员获取B实例
    const bInstance = (a as any).b;
    const stub = sinon.stub(bInstance, "someOtherFunction").resolves();
    
    const result = a.someFunction();
    expect(result).to.equal(42);
    expect(stub.calledOnce).to.be.true;
    
    stub.restore();
  })
})

方案对比

  • 推荐使用依赖注入:解耦类之间的依赖,让代码更易维护和测试,符合面向对象设计原则。
  • 若无法修改原代码,选择提前Stub原型方法:不破坏封装,对原有代码无侵入。
  • 尽量避免绕过私有成员:依赖内部实现,测试脆弱性高。

内容的提问来源于stack exchange,提问作者Surya Srivastava

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 12:50:21