Ionicテストの自動化テストの概念と実践

8849 ワード

Testing Concetps


外国の有料のionic学習サイトに翻訳すると、元の住所が貼れなくなります.
自動化テストは長い間現れ、テストに関する概念と最高の実践がたくさんあります.特定の言語はtestsを記述するために使用されますが、同じ概念はあなたが使用しているプログラミング言語で使用することができます.

AAA: Arrange, Act, Assert


これはあなたが理解する必要がある重点概念かもしれませんが、テストの作成を指導する原則です.テストコードを作成するには、次の手順に従います.
  • Arrange配置、配置がはっきりしている
  • Act実行
  • Assertアサーション
  • まず、テストに必要なステータスを設定し、コードを実行し、指定した結果が現れると断言する必要があります.
    この概念をどのように運用するかを見てみましょう.
    // Test that `incrementTotal()` increases the total by 1
    
    /* Arrange */
    let myTestObject = new SomeObject();
    
    /* Act */
    let oldTotal = myTestObject.getTotal();
    myTestObject.incrementTotal();
    
    let newTotal = myTestObject.getTotal();
    
    /* Assert */
    if(newTotal === oldTotal + 1){
        console.log("test passed!");
    } else {
        console.log("test failed!");
    }
    

    まず、arrangeテスト--テストするobjectを設定し、act-objectを呼び出す方法であり、最後にassert-newTotaloldTotal+1に等しい.
    後で、私たちのテストはもっと複雑になり、vanilla JavaScriptで似たようなコードを書くことはありません.しかし、Arrange,Act,Assertという概念はまだ使われています.

    One Assertion Per Test


    テストを作成する場合、1つのtestには通常1つのassertionしかありません.testは特定のことをテストする必要があります.もちろん、これは強制的ではありません.自分の考え通りに簡単に1つのtestの中でN以上のassertionをすることができます.しかし、一般的にはこれは良い考えではありません.
    このルールに違反するtestを見てみましょう.
    it('should allow todos to be modified', () =>{
    
        // trigger edit todo functionality
    
        // expect that the edit page was launched with the todo
    
        // trigger delete todo functionality
    
        // expect that the todo was passed to the delete function in the data provider
    
    });     
    
    todosが変更できるかどうかをテストします.実際には、todosが修正可能かどうか、todosが削除可能かどうかの2つのことがtestされます.どうしてこれは良い構造ではないと言ったのですか.
  • ぼやけている--should allow todos to be modifiedという説明はあまりにも広くて、testが何なのか一目ではわかりません.
  • テストに失敗した場合、どの断言に失敗したのか、編集に失敗したのか、削除に失敗したのか、具体的にはわかりません.それとも両方失敗したの?この2つのtestを分離すると、明らかになります.

  • 良い構造は次のようになります.
    it('delete function should pass the todo to the deleteTodo method in the provider', () => {
    
        // trigger delete function on the page
    
        // check that the deleteTodo method on the provider has been called
    
    });
    
    it('edit function should launch the EditTodo page and pass in the todo as a parameter', () => {
    
        // trigger edit function on the page
    
        // check that the navCtrl pushed the EditTodo page with the `todo` as a parameter
    
    });
    

    この2つのtest定義はよりよく、独立して実行されます.testの説明が長すぎることを心配する必要はありません.かえって長ければ長いほどいいです.結局、あなたの考えの改善と維持に役立ちます.

    Make Tests Independent


    前の例ではtestsが互いに独立している概念が概ね理解されている.前の例では、同じtestで2つのテストを実行したため、最初のテストは2番目のテストの動作を変更する可能性があります.
    タイムリーに同じtestで複数のテストを走っていないと、上記の問題に直面します.例:
    let groceryList = new GroceryList();
    
    it('we should be able to push items to the grocery list', () => {
    
        // push an item to the grocery list
    
        // check that it was added
    
    });
    
    it('the grocery list should be empty by default', () => {
    
        // check that the grocery list is empty
    
    }); 
    

    この場合、最初のテストは2番目のテストに干渉します.grocery listのデフォルトは空ですが、最初のテストにitemを追加するとデフォルトではありません.この問題を解決するには、各テストを実行する前にresetを保証する必要があります.たとえば、次のようにします.
    let groceryList;
    
    beforeEach(() => {
    
        groceryList = new GroceryList();
    
    });
    
    it('we should be able to push items to the grocery list', () => {
    
        // push an item to the grocery list
    
        // check that it was added
    
    });
    
    it('the grocery list should be empty by default', () => {
    
        // check that the grocery list is empty
    
    });
    

    各試験方法の前にbeforeEach方法を追加した.これは後述する

    Isolate Unit Tests

    one assertion per testの例では、deleteTodoメソッドの呼び出しをテストした.todoが本当に削除されたかどうかをテストしていません.
    この場合、todoの削除操作は、現在のpageの動作ではなく、todosのproviderを処理する.現在のpageはこのproviderに情報を伝えるだけで、これが私たちのテストの内容です.deletionプロセスが正しいことをテストするためにproviderに関連する独立したテストが必要です.
    1つのユニットテストでは、テストするコードは、APPの他の部分と完全に関係を断ち切る必要があります.dataを送信することはできません.serverのdataを引き継ぐことはできません.サーバにdataを送信することはできません.他の外部(テスト中ではありません)呼び出しもできません.
    テストの機能がserverリクエストに依存している場合、またはNavParamsを介して渡されるパラメータなどのデータを渡す必要がある場合は、二重テスト データを使用します.基本的な考え方は、NavParamsからデータを抽出してテストを実行する必要がある場合、実際にはNavParamsからデータを抽出する必要はありません.独自の偽実装NavParamsを使用してテストデータを転送することができます.サーバから応答を受信する必要がある場合は、実際のサーバに要求を発行しないで、要求をブロックし、自分の偽データを使用して応答する必要があります.
    最初はこれらを把握するのが難しいので、アプリが動作しているかどうかをテストしたいと思っています.なぜリクエストサーバを迂回して、私たちが知っている正しいdataに戻りますか?テストと他のコントロール、サービスの統合はユニットテストの一部ではありません.ユニットテストに興味があるのはunitそのものだけです.ユニットテストは、独立したコードブロックをテストすることについてです.

    Don't Try to Test Everything


    想像してみてください.私たちのユニットは1つの数が偶数かどうかを教えてくれる方法をテストします.テストはこうです.
    it('isEven function should return true for even numbers', () => {
    
        expect(isEven(4)).toBe(true);
    
    });
    
    it('isEven function should return false for odd numbers', () => {
    
        expect(isEven(5)).toBe(false);
    
    });
    

    この2つの試験は予想される結果を得ることができるが、これはisEvenがすべての数字を満たすことを意味しない.この点に基づいて、テストをよりrobustに変更することができます.
    そうするな
    it('isEven function should return true for even numbers', () => {
    
        for(i=0; i < 2000; i+=2){
            expect(isEven(i)).toBe(true);
        }
    
    });
    
    it('isEven function should return false for odd numbers', () => {
    
        for(i=1; i < 2000; i+=2){
            expect(isEven(i)).toBe(false);
        }
    
    });
    

    今、私たちがテストしたのは奇数や偶数ではなく、1000個です.これでもっといいですか?なぜ1万個か100万個ではないのですか?もしあなたが通信録に名前を指定する方法があるかどうかを検査するには、10万個の名前をテストするリストを作って、すべてテストする必要がありますか?
    すべての状況をカバーすることはできません.この必要もありません.あなたのテストも異常に時間がかかります.1つのテストデータはあなたのコードが正常に動作していることを証明することはできません.実際には、テストのコードが100%正しいことを保証することはできません.
    逆に, 例に焦点を当てた.既知の偶数と既知の奇数をテストすることができます.nameをチェックする例では、validのいくつかのname、およびinvalidのいくつかのnameを選択することができる.
    次の例はOne Assertion Per Testの原則を破った.同じ方法のために5つの独立したテストを書くつもりはありません.5つの異なる値をテストするために、isEvenを長くすることができます.
    it('isEven function should return true for even numbers', () => {
    
        expect(isEven(0)).toBe(true);
        expect(isEven(4)).toBe(true);
        expect(isEven(987239874)).toBe(true);
    
    });
    

    一般的にテストでループを使用しないでください.

    Mocks, Stubs, Spies


    前述したように、分離ユニット試験の 機能について議論した.それがmocks、stubs、spiesの根源です.
    Mocks and Stubs
    mockとstubは基本的に同じものです:その違いを理解することが重要で、後で議論します.両方とも、testのobjectは、自身が実装したfakeまたはdummyで置き換えられる.これに先立って,テストは異なるインタフェースから提供されるNavParamsからdataを取得することに依存するtestシナリオについて議論した.コード長はこうです.
    let myValue = this.navParams.get('someValue');
    
    Page2をテストしたい場合、NavParamsが提供するdataはPage1から来ており、他のコンポーネントのデータに依存できないため、セルテストに問題が発生します.
    実際のNavParamsを初期に自分で偽造した実装で置き換えることができます.例:
    class myFakeNavParams {
        public get(param: string): any {
            return 'hello!';
        }
    };  
    

    これにより、真のNavParamsのすべての機能が体現されるとともに、getの方法を置き換え、彼に何が伝わっても、hello!に戻るだけです.NavParamsの偽造版が完成した後、providersを設定するときにtestに偽造版を使うように伝えるだけです.
    providers: [
        ...
        { provide: NavParams, useClass: myFakeNavParams },
        ...
    ]   
    

    NOTE:このステップはtestの設定時に完了しましたので、後でこれについて議論します.あなたのアプリでこれを本物のproviderに置き換えないでください.
    この場合、testでNavParamsを参照するたびに、作成した偽造版に置き換えられます.前述したように、stubsとmocksは同じものに基づいています.本物のbehaviorを偽造behaviourで置き換えます.しかし、概念的な違いがある.
    この違いを説明するのは難しいが、私の頭の中の概念が100%正しいとは思わないし、何から構成されたmocksと何から構成されたstubsに100%の共通認識があるとは思わないので、違いが心配だ.
    私が最善の解釈を見つけることができるのは、通常stubsがテストのvaluesを返すために使用されることです.テストで使用する戻り値を偽造する場合はstubが必要です.つまり、上記の例は、以下の方法でより適切に使用できます.
    spyOn(navParams, 'get').and.returnValue('hello!');
    

    したがって、複雑なクラスを作成する必要はありません.簡単なstubを作成してvalueを返すだけです.しかし、testsは、偽造実装を提供したいobjectの構造に依存する場合がある.loadingのマスクを作成したい場合は、次のmockを作成できます.
    export class LoadingControllerMock {
      public create(): LoadingComponentMock {
        return new LoadingComponentMock();
      }
    }
    

    これは、テストからテストへの変更ではなく、実際のLoadingControllerの擬似実装です.これにより、loadingを作成するマスクをテストするときに、本物のマスクを使用しないことができます(使用すると隔離テストのルールが破られるため).
    簡単に言えば、stubsはtestで変更されるvaluesを偽造し、mocksはobjectの構造を偽造し、同じmockの異なるバージョンを作成しません.
    Spies
    Spiesはmocksとstubsに似ていて、spyのためにいくつかのものを出すことができます.一般的な使い方は以下の通りです.
    spyOn(someObject, 'someMethod');    
    

    この場合、そのobjectがその擬似実装に置き換えられるだけでなく、track someMethodメソッドの呼び出しも容易に行うことができる.テストのいずれかの点で、Spyはこの方法が呼び出されたかどうか、呼び出されたときに何の情報があったか、何回呼び出されたかなどを教えてくれます.

    Tests Are Not Fool Proof


    テストは万全ではないことを覚えておいてください.合格したテストでは、コードが正常に動作することは保証されません.もしあなたのテストコードがよく書けば、それはあなたのコードがしたいことをしていることを大きく説明しますが、100%保証することはできません.テストが間違っているか、指定したcaseを上書きしていないと失敗することがよくあります.