DiscourseのEmberコードに受け入れテストとコンポーネントテストを書く

自動テストは、将来の機能劣化(リグレッション)からコードを守るための優れた方法です。多くの人は、rspec を使用して Rails コードベースでこれを行う方法に慣れています。しかし、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 のセレクタにアクセスできます。ここでのアサーションは、そのセレクタを使用してスナックのタイトルと説明の値を取得し、期待値と比較しています。値が一致すればアサーションは合格し、テストは正常に動作しています。

ここで注意すべきは、このようなコンポーネントのすべての細かな部分をテストする必要はないということです。判断力を用いて、コードの中で何が壊れやすいか、あるいは将来他の開発者を混乱させる可能性があるかを検討してください。テンプレート内のテストが多すぎると、将来誰かが変更を行う際に負担が大きくなります。まずは小さく始めて、最も明らかなものからテストし、慣れてくれば自然とコツが掴めるでしょう。

受け入れテスト(Acceptance Tests)

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

/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 側と JavaScript 側があり、後者はデータを取得するために AJAX リクエストを実行していました。受け入れテストは 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 を試みることもできます。作業内容や個人の好みによっては、これがより楽しいアプローチになるかもしれません。幸運を祈り、楽しくコーディングしてください :slight_smile:


このドキュメントはバージョン管理されています - 変更提案は 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