数学者のようにテストを書く:パート2


もともと公開crunchingnumbers.live
ミントは、ボックスのテストの3種類を提供します:
  • 単体テスト
  • レンダリングテスト(以前は、統合テストとして知られている)
  • アプリケーションテスト(以前受け入れテストとして知られている)
  • 大まかに言えば、これらのテストは2つの面で異なります.
  • あなたのアプリケーションのどの部分は、正しさをチェックします.異なるタイプのテストをすることは、別々のテスト懸念を助けます.
  • 彼らはなんて速く走るのだろう.
  • 各タイプを見てみましょう.

    1単位試験

    定義
    単体テストは個々のメソッドと関数の正しさをチェックします.入力を与えられると、メソッドは正しい出力を返しますか?単体テストでは、メソッドレベルでコードをチェックすることができますので、テストスイートの基礎を作成できます.ユニットテストも非常に高速で自然です.
    UNIX CLIを作成するときに自動的にユニットテストが作成されますadapters , controllers , initializers , models , serializers , services , とユーティリティ.私は将来のブログ記事の各テストを書くことを望む.

    b .なぜそれらを使用する?
    単体テストの利点は三倍です.
    つの、単体テストは一般に孤立して、個々の方法と機能に集中するので、あなたのテストが失敗するとき、デバッグするのは簡単です.
    つの、ユニットテストを使用すると、高レベルのテストで練習するのが難しいかもしれないロジックの小さな部分に集中することができます.
    最後に、ユニットテストは非常に高速で実行されるので、テストスイートのパフォーマンスに最小限の影響を与える引数の多くの置換を確認することができます.

    c .例
    以下のコードは、単体テストが個々のメソッドをチェックする方法を示しています.私たちのアプリは、私たちが数字で動作するユーティリティを持って想像してください.
    File: /tests/unit/math-library-test.js
    
    import { module, test } from 'qunit';
    import { getDivisors, isPrime } from 'our-app-name/utils/math-library';
    
    module('Unit | Utility | math-library', function() {
        test('should check if a number is prime', function(assert) {
            assert.strictEqual(isPrime(1), false);
            assert.strictEqual(isPrime(2), true);
            assert.strictEqual(isPrime(3), true);
            assert.strictEqual(isPrime(4), false);
            assert.strictEqual(isPrime(5), true);
            assert.strictEqual(isPrime(6), false);
        });
    
        test('should get all divisors of a number', function(assert) {
            assert.deepEqual(getDivisors(1), [1]);
            assert.deepEqual(getDivisors(2), [1, 2]);
            assert.deepEqual(getDivisors(3), [1, 3]);
            assert.deepEqual(getDivisors(4), [1, 2, 4]);
            assert.deepEqual(getDivisors(5), [1, 5]);
            assert.deepEqual(getDivisors(6), [1, 2, 3, 6]);
        });
    });
    
    単体テストが理想的な例です.
  • コントローラの内部では、計算されたプロパティはフィルターを続けますthis.model 正しく動作した後
  • チェック方法 normalize() Serializerでデータを受信する
  • チェック方法 serialize() シリアライザーでデータを送信する
  • エーcron ユーティリティは、入力文字列を、UI

  • 何を気にする
    Unitフレームワークが含まれるときは、インポートとコールする必要があります setupTest() , その後、hooks オブジェクト.心配しないで.Ember CLI あなたのためにこれを行います!)
    たとえば、メッセージの配列を保持するサービスを考慮します.
    File: /tests/unit/services/flash-messages-test.js
    
    import { setupTest } from 'ember-qunit';
    import { module, test } from 'qunit';
    
    module('Unit | Service | flash-messages', function(hooks) {
        setupTest(hooks);
    
        test('should be able to buffer messages', function(assert) {
            let service = this.owner.lookup('service:flash-messages');
    
            service.add('Hello');
            service.add('World!');
    
            assert.deepEqual(service.get('messages'), ['Hello', 'World!']);
        });
    });
    
    呼び出しによってsetupTest() , あなたはいくつかのものへのアクセスを得る.最初は、LabsのものですDependency Injection システム要するに、あなたはlook up あなたのアプリケーションの何か、少しの助けを借りてthis.owner . 第二に、いくつかの一般的なユーティリティ関数へのアクセスを得るthis.get() and this.set() , テストで.最後に、使用することができますpauseTest() to debug your tests .

    レンダリングテスト

    定義
    レンダリングテスト(統合テスト)コンポーネントの外観と動作を確認します.レンダリングテストを作成するcomponents and helpers .
    パフォーマンスに関しては、レンダリングテストは中央、ユニットとアプリケーションテストの間に座ります.

    b .なぜそれらを使用する?
    あなたのアプリケーションは、複数のコンポーネントで構成されているので、各グループとしてテストする前に、それぞれが正しいことを確認したい.コンポーネントが再利用可能であるならば、あなたはarguments and actions .
    レンダリングテストでは、Memberのレンダリングエンジンを使用してコンポーネントをテストできます.これは、あなたのレンダリングテストで作成されたコンポーネントは、実際のアプリケーションで動作するように動作します.コンポーネントがそのライフサイクルフックに従うことを保証します.また、エンドユーザーのようなコンポーネントと対話することができます.

    c .例
    ボタンコンポーネントを考えます.簡単にするために、コンポーネントがクリック数を追跡し、ラベルとして表示すると仮定します.(つまり、このコンポーネントは引数やアクションを渡すことができません.
    File: /tests/integration/components/simple-button-test.js
    
    import { click, render } from '@ember/test-helpers';
    import { hbs } from 'ember-cli-htmlbars';
    import { setupRenderingTest } from 'ember-qunit';
    import { module, test } from 'qunit';
    
    module('Integration | Component | simple-button', function(hooks) {
        setupRenderingTest(hooks);
    
        test('should keep track of clicks', async function(assert) {
            await render(hbs`<SimpleButton />`);
            assert.dom('[data-test-label]').hasText('0 clicks');
    
            await click('[data-test-button]');
            assert.dom('[data-test-label]').hasText('1 click');
    
            await click('[data-test-button]');
            assert.dom('[data-test-label]').hasText('2 clicks');
        });
    });
    
    注:インポートrender and click から@ember/test-helpers コンポーネントを表示および対話するには.また、輸入hbs からember-cli-htmlbars インラインテンプレートの定義を支援する.これらのメソッドを使用すると、コンポーネントをクリックすると、ユーザーに出力を正しく更新するかどうかを確認できます.
    レンダリングテストが理想的な例を以下に示します.
  • ブログポストコンポーネントは、2つのモードを表示および編集することができます
  • ボタンコンポーネントは、さまざまな引数とアクションのアクセシビリティを満たす
  • ナビゲーションコンポーネントを再帰的に子ナビゲーション項目をレンダリング
  • 使用するヘルパー Intl.NumberFormat , 表示する通貨と数字の数に応じて価格をフォーマットする

  • 何を気にする
    テストをレンダリングするには、コールする必要があります setupRenderingTest() とパスhooks オブジェクト.
    何がsetupRenderingTest() どうする?最初に、setupTest() 舞台裏で.ユニットテストと同じようにthis.owner , this.get() , this.set() , and pauseTest() .
    加えてsetupRenderingTest() レンダリングやDOM相互作用のためのヘルパーを使用しますrender , click , and fillIn . また、使用することができますthis.element 結果のDOM要素にアクセスするにはrender .

    アプリケーションテスト

    定義
    あなたはエンドユーザーの視点からユーザーストーリーや機能を確認するためにアプリケーションテスト(受入テスト)を使用することができます.あなたは、ユーザーがホームページを訪問し、自分自身を認証するために、別のページに移動するには、フォームを埋めるために、などと同じように、アプリケーションと対話します.
    アプリケーションのテストは、Beanアプリケーションのインスタンスを作成するため、単位とレンダリングのテストより遅くなります.

    b .なぜそれらを使用する?
    アプリケーションのテストを使用すると、別のコンポーネントを相互作用する方法を見るのに役立ちます.入れ子になった、またはコンテキストのコンポーネントについては、レンダリングテストで取得できます.コンポーネントが無関係であるならば、アプリケーションテストは唯一の方法かもしれません.
    また、ルーティングをチェックするアプリケーションテストを使用することができます.つのページから別のユーザーに移動できますか?ページがロードされるとき、彼らは正しいコンポーネントを見ますか?これは、アプリケーションのテストでこれらをチェックしやすいです.
    最後に、アプリケーションがデータを受信して送信する場合は、これらのアクションを正常に実行できることを保証します.また、エラー状態を正しく処理できることを証明します.アプリケーションのテストは、このように、ユーザーと同じようにアプリケーションと対話する必要がありますので、これらをチェックする素晴らしい場所です.

    c .例
    レンダリングテストからブログ投稿例を続けましょう.我々のブログポスト構成要素が2つのモードを見ることができて、編集するのを思い出してください.次のテストはブログ投稿を作成する一つの方法です.
    File: /tests/acceptance/posts-test.js
    
    import { click, currentURL, fillIn, visit } from '@ember/test-helpers';
    import { setupApplicationTest } from 'ember-qunit';
    import { module, test } from 'qunit';
    
    module('Acceptance | posts', function(hooks) {
        setupApplicationTest(hooks);
    
        test('The user can create a blog post', async function(assert) {
            await visit('/posts/new');
            await fillIn('[data-test-field="Title"]', 'My New Post');
            await fillIn('[data-test-field="Content"]', 'Lorem ipsum dolor sit amet');
            await click('[data-test-button="Save"]');
    
            // The user is redirected to their new post
            assert.strictEqual(currentURL(), '/posts/1');
            assert.dom('[data-test-field="Title"]').hasText('My New Post');
            assert.dom('[data-test-field="Content"]').hasText('Lorem ipsum dolor sit amet');
        });
    });
    
    何があなたのためにテストすることができます他のものですか?
  • ユーザはブログ記事を読む、更新、削除することができます(バッチ操作で)
  • ユーザーがブログ記事にコメントをすることができます
  • ユーザーはブログ投稿を共有することができます
  • ユーザーは、ブログに行動を起こす権限があるべきです
  • エラーがある場合、ユーザはフィードバックを受け取る

  • 何を気にする
    気をつけるべきことがいくつかあります.
    最初に、アプリケーションのテストを実行する時間です.小さなアプリのために、その影響は最小限です.しかし、大きなアプリケーションのために、短いフィードバックループを維持することは重要になります.これらの場合では、単位またはレンダリングのテストを使用してアプリケーションのシナリオを確認できる場合は、代わりにそれらを検討することができます.
    第二に、アプリケーションのテストを作成するには、MINT CLIを使用できます.アプリケーションのテストは、あなたのアプリケーションで何かをカバーすることができますので、いくつかの自然な方法でファイルを整理する必要があります.これはすぐにテストを見つけ、重複を防ぐのに役立ちます.
    整理する一つの方法は、フォルダ構造を模倣することですapp/routes . つまり、ルートごとにアプリケーションテストファイルを作成します.これがあまりにも多くのファイルをもたらす場合は、代わりに各親ルートのファイルを作成することができます.
    最後に、アプリケーションのテストを行うためには、コールする必要があります setupApplicationTest() とパスhooks オブジェクト.いつもの善良さに加えてsetupTest() , このメソッドは、エンドユーザーの視点からアプリケーションをテストできるようにアプリケーションインスタンスを作成します.また、ルーティングやDOMインタラクションなどのテストヘルパーを使用できますcurrentURL , visit , click , and fillIn .

    まとめ
    我々は、デフォルトでは、ミントは、テストの3種類を提供しています:ユニット、レンダリング、およびアプリケーションのテストを学んだ.
    これらのテストは、論理的な結論に到達するためにあなたのアプリケーションのどのように多くの部分を統合しています.一方、単体テストでは、コードのセクションを分離してチェックできます.他方では、アプリケーションのテストでは、エンドユーザーとしてあなたの全体のアプリケーションを体験させてください.
    corollaryは、これらのテストがパフォーマンスにおいて異なるということです.より多くの部品(実際のアプリに近い)、低速テストを使用します.あなたのアプリが大きくなるにつれて、あなたは、幅広いテストカバレッジと短いフィードバックループを楽しむことができるように、ユニット、レンダリング、およびアプリケーションのテストの健全なミックスを維持したいと思います.
    次回は、テストを書くためのベストプラクティスを見ていきます.

    ノート
    とても感謝しますTodd Jordan . 彼はこのポストを校正し、多くの素晴らしい提案を提供するために時間がかかりました.