Angularユニットテストシリーズ-Jasmineを使用してAngularユニットテストを行う方法


以下は私がユニットテストを書いていない人やほとんど書いていない人が準備したと仮定しているので、多くの概念的な問題を白話で説明し、Jasmineと対応する方法を組み合わせて説明します.

一、概念


Test Suite


テストキットは、単純なクラスでもいくつかのテスト例があるので、これらのテスト例を1つの分類にまとめてTest Suiteと呼びます.
Jasmineではdescribeのグローバル関数を使用して表され、最初の文字列パラメータはSuiteの名前やタイトルを表すために使用され、2番目の方法パラメータはSuiteコードを実現することです.
describe('test suite name', () => {
});

Specs


1つのSpecsは、テストの例に相当します.つまり、テストの特定のコード体を実装します.
Jasmineは、itのグローバル関数を使用して表され、describeと同様に、文字列と方法の2つのパラメータです.
各Specには、テストが必要なコードをテストするために複数のexpectationが含まれており、いずれかのexpectation結果がfalseであれば、テスト例が失敗したことを示す.
describe('demo test', () => {
    const VALUE = true;
    it('should be true', () => {
        expect(VALUE).toBe(VALUE);
    })
});

Expectations

expectグローバル関数を使用して表現すると、テストを表す実際の値が1つしか受信されず、Matcherと所望の値を表す必要があると断言する.

二、常用方法


Matchers


照合操作を断言し、実際の値と期待値との比較を行い、結果をJasmineに通知すると、最終的にJasmineはこのSpecが成功したか失敗したかを判断します.
Jasmineは非常に豊富なAPIを提供し、いくつかのよく使われるMatchers:
  • toBe()同等===
  • toNotBe()等!==
  • toBeDefined()等!== undefined
  • toBeUndefind()は=== undefined
  • に等しい.
  • toBeNull()等=== null
  • toBeTruthy()等!!obj
  • toBeFalsy()等!obj
  • toBeLessThan()は<
  • に等しい
  • toBeGreaterThan()は>
  • に等しい.
  • toEqual()は==
  • に相当する.
  • toNotEqual()は!=
  • に相当する.
  • toContain()はindexOf
  • に相当する.
  • toBeCloseTo()数値比較で精度を定義し、四捨五入してから比較します.
  • toHaveBeenCalled()functionが呼び出されたかどうかを確認する
  • toHaveBeenCalledWith()入力パラメータがパラメータとして呼び出されたかどうかを確認する
  • .
  • toMatch()等new RegExp().test()
  • toNotMatch()等!new RegExp().test()
  • toThrow()functionがエラーを投げ出すかどうかをチェック
  • これらのAPIは、以前はnotで負の値の判断を表していた.
    expect(true).not.toBe(false);

    これらのMatchersはほとんど私たちの日常的なニーズを満たすことができます.もちろん、独自のMatcherをカスタマイズして特別なニーズを実現することもできます.

    SetupとTeardown


    幹将のテストコードは重要であるため、これらの繰り返しsetupとteardownコードを、それに対応するbeforeEachafterEachのグローバル関数の中に置くことができます.beforeEachは、各Specが実行される前、逆を表す.
    describe('demo test', () => {
        let val: number = 0;
        beforeEach(() => {
            val = 1;
        });
        it('should be true', () => {
            expect(val).toBe(1);
        });
        it('should be false', () => {
            expect(val).not.toBe(0);
        });
    });

    データ共有


    上記の例と同様に、各describeの内部で共有できるように、各テストファイルの先頭、itで対応する変数を定義することができる.
    もちろん、各Specの実行週期間は、1つの空のthisオブジェクトを伴い、Specの実行が終了するまでクリアされ、thisを利用してデータ共有も可能である.

    ネストコード


    あるコンポーネントをテストすると、このコンポーネントは異なる状態で異なる結果を示すことがあります.この場合、describeだけでは優雅に見えません.
    したがって、describeをネストすると、テストコード、テストレポートがよりきれいに見えます.
    describe('AppComponent', () => {
        describe('Show User', () => {
            it('should be show panel.', () => {});
            it('should be show avatar.', () => {});
        });
        describe('Hidden User', () => { 
            it('should be hidden panel.', () => {});
        });
    });

    テストコードブロックをスキップ


    需要はいつも三昧だが、せっかく書いたテストコードを削除するのか.いや...
    SuitesおよびSpecsは、これらのテストコードブロックをスキップするために、それぞれxdescribeおよびxitのグローバル関数を使用することができる.

    三、Angularツールセットに合わせる


    Spy


    Angularのカスタムイベントはあまりにも一般的ですが、これらのカスタムイベントをテストするためには、イベントが正常に呼び出されているかどうかを監視することが重要です.幸いなことに、Spyは関数が呼び出されるかどうかを監視するために使用することができます.これは私たちの良いパートナーです.
    以下の例はしばらく気にしないで、しばらく体験してみましょう.
    describe('AppComponent', () => {
        let fixture: ComponentFixture;
        let context: TestComponent;
    
        beforeEach(() => {
            TestBed.configureTestingModule({
                declarations: [TestComponent]
            });
            fixture = TestBed.createComponent(TestComponent);
            context = fixture.componentInstance;
            //   onSelected  
            spyOn(context, 'onSelected');
            fixture.detectChanges();
        });
    
        it('should be called [selected] event.', () => {
            //   selected  
    
            //         
            expect(context.onSelected).toHaveBeenCalled();
        });
    });

    非同期のサポート


    まず、ここでの非同期とは、ObservableまたはPromiseを伴う非同期動作であるため、コンポーネントがサービスを呼び出してデータを非同期で取得するときのテストステータスである.
    テスト対象のコンポーネントコードを仮定します.
    export class AppComponent {
      constructor(private _user: UserService) {}
    
      query() {
        this._user.quer().subscribe(() => {});
      }
    }

    async asyncはパラメータと戻り値がなく、すべてのラップコードブロックのテストコードは、whenStable()を呼び出すことで、処理される非同期動作をすべて完了させてからコールバックすることができる.最後に、断言操作を行います.
    it('should be get user list (async)', async(() => {
        // call component.query();
        fixture.whenStable().then(() => {
            fixture.detectChanges();
            expect(true).toBe(true);
        });
    }));

    fakeAsync asyncがブレークポイントに耐えられないようにコールバックする必要があるとすれば、fakeAsyncはこの点を解決することができます.
    it('should be get user list (async)', fakeAsync(() => {
        // call component.query();
        tick();
        fixture.detectChanges();
        expect(true).toBe(true);
    }));

    ここはコールバックをtick()に変えただけで、どうですか.かっこいいですか.
    Jasmineは非同期を持っています
    前述したように非同期とは、ObservableやPromiseを伴う非同期行為を指しますが、setTimeoutに依存しているものや、外部購読結果が必要になってからトリガーされる場合はどうすればいいのでしょうか.done()の方法を使用することができる.
    it('async demo', (done: () => void) => {
        context.show().subscribe(res => {
            expect(true).toBe(true);
            done();
        });
        el.querySelected('xxx').click();
    });

    四、結論


    この章のほとんどの内容はAngularユニットでよく使われるものをテストします.特に非同期部分では,3つの異なる非同期方式が共存するのではなく,具体的な業務に応じて採用する必要がある.そうでなければ、真TMの書き込みが難しいユニットテストが見つかります.結局これは非同期の世界です.
    それ以来,Angular書き込みユニットテストの基礎を築いた.その後、このような基礎は説明されません.
    それでは次の記事では、Component、Directive、PipeおよびServiceユニットテストをご紹介します.
    happy coding!