web-dev-qa-db-fra.com

Comment stub une méthode privée d'une classe écrite en TypeScript en utilisant sinon

J'écris des tests unitaires pour une méthode publique qui, à son tour, appelle une méthode privée de la classe écrite en TypeScript (Node JS).

Exemple de code

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

Maintenant, pour tester method1 (), j'ai besoin de stub method2 () qui est une méthode privée.

voici ce que j'essaye:

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

TypeScript lance l'erreur:

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

Toute aide serait appréciée. Merci

16
SHRUTHI BHARADWAJ

Le problème est que la définition de sinon utilise la définition suivante pour la fonction stub:

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

Cela signifie que le deuxième paramètre doit être le nom d'un membre (public) de type T. C'est probablement une bonne restriction en général, mais dans ce cas, c'est un peu trop restrictif.

Vous pouvez le contourner en effectuant un cast vers any:

sinon.stub(A.prototype, <any>"method2");

Parfois, lorsque la complexité du code et des tests est plus importante, je préfère "externaliser" les méthodes privées. Vous pouvez le faire, que ce soit avec une classe (partielle) ou une interface (partielle).

    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);
    });

REMARQUE: si vous contrôlez le code que vous testez, vous n'avez pas besoin de doubler le code, sujet aux erreurs, mais vous pouvez faire en sorte que votre classe implémente l'interface. Pour convertir une interface standard (sans privé) en "externalisée", vous pouvez l'étendre avec des méthodes publiques.

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