如何用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
相关产品推荐
相关产品推荐

