TypeScript(Node JS)で記述されたクラスのプライベートメソッドを呼び出すパブリックメソッドの単体テストを作成しています。
サンプルコード
class A {
constructor() {
}
public method1() {
if(this.method2()) {
// Do something
} else {
// Do something else
}
}
private method2() {
return true;
}
}
次に、method1()をテストするために、プライベートメソッドであるmethod2()をスタブする必要があります。
ここで私が試していること:
sinon.stub(A.prototype, "method2");
TypeScriptがエラーをスローしています:
Argument of type '"method2"' is not assignable to parameter of type '"method1"'
任意の助けいただければ幸いです。ありがとうございました
問題は、sinon
の定義がstub
関数の次の定義を使用することです。
interface SinonStubStatic { <T>(obj: T, method: keyof T): SinonStub; }
つまり、2番目のパラメーターはT
タイプのメンバー(パブリックパラメーター)の名前でなければなりません。これはおそらく一般的に良い制限ですが、この場合は少し制限が多すぎます。
any
にキャストすることで回避できます:
sinon.stub(A.prototype, <any>"method2");
コードとテストの複雑さがより重要な場合、私はプライベートメソッドを「外部化」することを好むことがあります。 (部分)クラスまたは(部分)インターフェースのいずれかでそれを行うことができます。
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);
});
注:テストするコードを制御する場合、コードを2重にする必要はなく、間違いが起こりやすくなりますが、クラスにインターフェイスを実装させることができます。標準(プライベートなし)インターフェースを「外部化された」インターフェースに変換するには、パブリックメソッドで拡張できます。
export interface IAExternalized extends IAPrivate {
method2():boolean
};