为 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 个赞