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 件のアサーションのうち 2 件が合格、0 件が失敗」といった出力を表示します。

/qunit ページでは他のテストも実行できる点に注意してください。画面上部の Module ドロップダウンから新しいテストを選択するだけです。

テストがどのように機能するかを理解するために、一歩ずつ見ていきましょう。

template 行は、Ember にコンポーネントを挿入する方法を伝えます。これは、コンポーネントをハンドルバーズテンプレートに配置する際に使用するマークアップと完全に同じです。そのため、馴染みがあるはずです。

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 側と 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 で応答する」と読むことができます。

URL /qunit?module=Acceptance%3A%20Snack を更新すると、受入テストは 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