Discourse の Ember コードに対する受け入れテストとコンポーネントテストを作成する

自動テストは、将来の回帰からコードを保護するための優れた方法です。多くの人は、Railsコードベースでrspecを使ってこれを行う方法に精通していますが、Javascript側は一部の人にとっては謎めいたものになることがあります。

幸いなことに、今日ではEmberコードに基本的なテストを追加するのはかなり簡単です!

コンポーネントテスト

このシリーズの前のチュートリアルでは、スナックをフェードする背景で表示するためにfancy-snackというコンポーネントを追加しました。それのためにテストを書きましょう。次のファイルを作成します。

test/javascripts/components/snack-test.js

import componentTest from "helpers/component-test";

moduleForComponent("fancy-snack", { integration: true });

componentTest("test the rendering", {
  template: "{{fancy-snack snack=testSnack}}",

  setup() {
    this.set("testSnack", {
      name: "Potato Chips",
      description: "Now with extra trans fat!",
    });
  },

  test(assert) {
    assert.equal(this.$(".fancy-snack-title h1").text(), "Potato Chips");
    assert.equal(
      this.$(".fancy-snack-description p").text(),
      "Now with extra trans fat!"
    );
  },
});

テストを実行するには、開発サーバーで/qunit?module=component%3Afancy-snackにブラウザを開きます。その後、ブラウザがコンポーネントテストを実行し、「2 assertions of 2 passed, 0 failed」のような出力が表示されます。

/qunitページにいる間は、他のテストを実行できることに注意してください。画面上部のModuleドロップダウンボックスから新しいテストを簡単に選択できます。

テストの仕組みを理解するために、ステップごとに見ていきましょう。

template行は、コンポーネントをどのように挿入したいかをEmberに伝えます。これは、handlebarsテンプレートでコンポーネントを配置するときに使用するのと同じマークアップなので、馴染みがあるはずです。

template: '{{fancy-snack snack=testSnack}}',

これは、testSnacksnackパラメーターとして渡していることに注意してください。これはsetup()メソッドで定義されています。

setup() {
  this.set('testSnack', {
    name: 'Potato Chips',
    description: 'Now with extra trans fat!'
  });
},

ここにダミーデータを入れました。Emberにコンポーネントを描画させるために必要なのはこれだけです。最後に、test()メソッドにいくつかのアサーションがあります。

test(assert) {
  assert.equal(this.$('.fancy-snack-title h1').text(), 'Potato Chips');
  assert.equal(this.$('.fancy-snack-description p').text(), 'Now with extra trans fat!');
}

this.$()を使用すると、テンプレート内のjQueryセレクターにアクセスできます。ここでのアサーションは、そのセレクターを使用してスナックのタイトルとスナックの説明の値を取得し、期待される値と比較します。値が一致すれば、アサーションは合格し、テストはすべて機能します。

このようなコンポーネント内のすべてをテストする必要はないことに注意する価値があります。裁量を使用し、コード内の何が将来壊れたり、他の開発者に混乱を招いたりする可能性があるかを把握するように努めるべきです。テンプレートでテストが多すぎると、将来誰かがそれを変更するのが面倒になります。まずは小さく、最も明白なことからテストを始め、時間とともに慣れていくでしょう。

受け入れテスト

受け入れテストは、記述が容易で、ユーザーがブラウザで行うのと同じようにアプリケーションをテストするため、コンポーネントテストよりも強力な場合があります。私は受け入れテストから始めることが多く、複雑なコンポーネントを作成している場合は、それらのテストも追加します。

/admin/snackルートにアクセスし、スナックがレンダリングされたことを確認する受け入れテストを次に示します。

test/javascripts/acceptance/snack-test.js

import { acceptance } from "helpers/qunit-helpers";
acceptance("Snack");

test("Visit Page", function (assert) {
  visit("/admin/snack");
  andThen(() => {
    assert.ok(exists(".fancy-snack-title"), "the snack title is present");
  });
});

この場合のtest()は、ほとんど英語のように読めます!最初のコマンドは、/admin/snackのURLにアクセスするように指示します。その後ろにはandThen()メソッドがあります。このメソッドは、テストが続行される前にすべてのバックグラウンド作業が完了していることを確認するために必要です。JavascriptとEmberのコードは非同期であるため、アサーションが実行される前にEmberが必要なすべての処理を完了していることを確認する必要があります。最後に、.fancy-snack-title要素が存在するかどうかをテストします。

しかし、/qunit?module=Acceptance%3A%20Snackにアクセスしてこのテストを実行すると、AJAXエラーのためにテストが失敗することになります。

思い出していただければ、私たちのコードにはRails側と、データを取得するためにAJAXリクエストを実行したJavascript側の両方が含まれています。受け入れテストはJavascript側を実行しましたが、Railsからデータを取得するために何をすべきかわかりませんでした。

これを修正するには、優れたpretenderライブラリを使用して、偽の応答を追加する必要があります。test/javascripts/helpers/create-pretender.jsファイルを開き、次の行を探します。

this.get("/admin/plugins", () => response({ plugins: [] }));

そのすぐ下に、受け入れテストが処理できるように偽のスナックオブジェクトを返す行を追加します。

this.get("/admin/snack.json", () => {
  return response({ name: "snack name", description: "snack description" });
});

上記のコードは、「/admin/snack.jsonへのすべてのリクエストに対して、次のresponseで応答する」と読むことができます。

/qunit?module=Acceptance%3A%20SnackのURLを更新すると、受け入れテストはpretender経由でデータを取得し、テストは合格するはずです。

これからどこへ行くか

小さな機能を作成し、それが機能することを確認するためのテストを追加することを試みるかもしれません。フロントエンドでコードを書く前にテストを作成することで、TDDを使用することを試みることもできます。取り組んでいるものや個人の好みに応じて、このアプローチの方が楽しいと感じるかもしれません。頑張ってください、そしてハッピーコーディングを: )


このドキュメントはバージョン管理されています - 変更の提案はgithubで行ってください。

「いいね!」 15

My prior experience in writing qunit tests was based on the other howto

i.e. “acceptance” was simply

acceptance("Purple Tentacle", { loggedIn: true });

I have seen in other plugins where the test code contained “fake” JSON to test against. I wasn’t sure if that would be as good as testing against “real” data, so I wanted to avoid doing it that way.

The six tests passed, but I got a couple of rather angry looking “unhandled request” errors.

After finding an example of some “setup” code, I tried it and it solved the errors.

It works, but I’m not really sure why, nor why it’s needed for some but not for the majority of plugins I’ve seen that have qunit tests.

「いいね!」 3

For a long time we weren’t great with testing plugins, so not many people followed our example and added tests.

You are right to add a response using pretender to handle AJAX calls.

「いいね!」 4

/qunit パスは廃止されたというお知らせです。現在は /tests です。見つけるのに少し時間がかかりました :slight_smile:

「いいね!」 1