Jasmine を使って Angular / TypeScript のプライベートメソッドのユニットテストを書く方法 質問する

Jasmine を使って Angular / TypeScript のプライベートメソッドのユニットテストを書く方法 質問する

Angular 2 でプライベート関数をテストするにはどうすればよいですか?

class FooBar {

    private _status: number;

    constructor( private foo : Bar ) {
        this.initFooBar();

    }

    private initFooBar(){
        this.foo.bar( "data" );
        this._status = this.fooo.foo();
    }

    public get status(){
        return this._status;
    }

}

私が見つけた解決策

  1. テスト コード自体をクロージャ内に配置するか、外部スコープ内の既存のオブジェクトのローカル変数への参照を格納するコードをクロージャ内に追加します。

    後でツールを使用してテスト コードを削除します。http://philipwalton.com/articles/how-to-unit-test-private-functions-in-javascript/

この問題を解決するより良い方法があれば、教えてください。

追伸

  1. このような質問に対する回答のほとんどは問題の解決策を示していないので、私はこの質問をしているのです

  2. ほとんどの開発者は、プライベート関数をテストしないと言いますが、それが間違っているとか正しいとか言うつもりはありません。ただ、私のケースではプライベートをテストする必要があるのです。

ベストアンサー1

私も同感です。「パブリック API のみを単体テストする」というのは良い目標ですが、それほど単純ではないように思え、API と単体テストのどちらかを妥協しなければならないと感じるときがあります。これはまさにあなたが求めていることなので、すでにご存知だと思いますので、ここでは触れません。:)

TypeScript では、ユニットテストのためにプライベート メンバーにアクセスする方法がいくつかあることを発見しました。次のクラスを考えてみましょう。

class MyThing {

    private _name:string;
    private _count:number;

    constructor() {
        this.init("Test", 123);
    }

    private init(name:string, count:number){
        this._name = name;
        this._count = count;
    }

    public get name(){ return this._name; }

    public get count(){ return this._count; }

}

TS は、、、を使用してクラス メンバーへのアクセスを制限しますが、privateコンパイルされた JS にはプライベート メンバーがありません。これは JS には存在しないためです。これは純粋に TS コンパイラーに使用されます。したがって、protectedpublic

  1. anyアクセス制限についてコンパイラに警告しないようにアサートして回避することができます。

    (thing as any)._name = "Unit Test";
    (thing as any)._count = 123;
    (thing as any).init("Unit Test", 123);
    

    このアプローチの問題点は、コンパイラが の直後に何を実行しているのかまったくわからないanyため、必要な型エラーが発生しないことです。

    (thing as any)._name = 123; // wrong, but no error
    (thing as any)._count = "Unit Test"; // wrong, but no error
    (thing as any).init(0, "123"); // wrong, but no error
    

    これにより、明らかにリファクタリングがより困難になります。

  2. 配列アクセス ( []) を使用してプライベート メンバーにアクセスできます。

    thing["_name"] = "Unit Test";
    thing["_count"] = 123;
    thing["init"]("Unit Test", 123);
    

    奇妙に見えますが、TSC は実際には直接アクセスしたかのように型を検証します。

    thing["_name"] = 123; // type error
    thing["_count"] = "Unit Test"; // type error
    thing["init"](0, "123"); // argument error
    

    正直に言うと、なぜこれが機能するのか分かりません。 どうやらこれは意図的な「脱出口」型の安全性を失うことなくプライベート メンバーにアクセスできるようにします。これはまさにユニット テストに必要なことだと思います。

がここにありますTypeScript Playground での動作例

TypeScript 2.6 用に編集

他にも、// @ts-ignoreTS 2.6 で追加) は、次の行のすべてのエラーを単純に抑制します。

// @ts-ignore
thing._name = "Unit Test";

これの問題点は、次の行のすべてのエラーが抑制されることです。

// @ts-ignore
thing._name(123).this.should.NOT.beAllowed("but it is") = window / {};

私は個人的には@ts-ignoreコード臭だと考えていますが、ドキュメントには次のように書かれています。

このコメントは控えめに使用することをお勧めします。[強調は原文のまま]

おすすめ記事