如何使用sinon存储用typescript编写的类的私有方法

时间:2017-11-22 10:45:14

标签: node.js unit-testing typescript sinon

我正在为一个公共方法编写单元测试,而该方法又调用了用typescript(Node JS)编写的类的私有方法。

示例代码

class A {
   constructor() {  
   }
   public method1() {  
       if(this.method2()) {
          // Do something
       } else {
          // Do something else
       }
   }
   private method2() {
      return true;
   }
}

现在测试method1()我需要stub方法2()这是一个私有方法。

在这里我正在尝试:

sinon.stub(A.prototype, "method2");

Typescript抛出错误:

Argument of type '"method2"' is not assignable to parameter of type '"method1"'

任何帮助将不胜感激。 谢谢

2 个答案:

答案 0 :(得分:9)

问题是sinon的定义对stub函数使用以下定义:

interface SinonStubStatic { <T>(obj: T, method: keyof T): SinonStub; }

这意味着第二个参数必须是T类型的成员(公共成员)的名称。这通常是一个很好的限制,但在这种情况下,它有点过于严格。

您可以通过转换为any

来绕过它
sinon.stub(A.prototype, <any>"method2");

答案 1 :(得分:0)

有时候,当代码和测试的复杂性变得更加重要时,我倾向于将外部方法“外部化”。您可以通过(部分)类或(部分)接口来做到这一点。

    it('private methods test', async () => {
        // original class
        class A{
            public method1():string{
                if(this.method2()) {
                    // Do something
                    return "true";
                 } else {
                    // Do something else
                    return "false";
                 }
            }
            // with private method
            private method2():boolean{
                return true;
            }
        }

        // interface that makes the private method public
        interface IAExternalized{
            method2():boolean;
        }

        // class that makes the private method public
        class APrivate implements IAExternalized{
            // with public method
            method2():boolean{
                return true;
            };
        }

        // test before mocking
        let test:A = new A();
        let result:string = test.method1();
        result.should.be.equal("true");

        // let's mock the private method, but with typechecking available
        let stubMethod2:sinon.SinonStub = sinon.stub(<IAExternalized><unknown>(A.prototype), "method2").returns(false);

        result = test.method1();
        result.should.not.be.equal("true");
        result.should.be.equal("false");

        // access private method of an object through public-interface
        let testPrivate:IAExternalized = <IAExternalized><unknown>test;
        let result2:boolean = testPrivate.method2();
        result2.should.not.be.equal(true);
        result2.should.be.equal(false);
    });

注意:如果您控制要测试的代码,则无需重复代码,容易出错,但是可以使您的类实现该接口。要将标准(无私有)接口转换为“外部”,可以使用公共方法进行扩展。

export interface IAExternalized extends IAPrivate {
   method2():boolean
};