为 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 个断言中 2 个通过,0 个失败”的结果。

请注意,在 /qunit 页面上,你还可以运行其他测试。你只需从屏幕顶部的 Module 下拉框中选择一个新的测试即可。

让我们逐步分析该测试,以了解其工作原理。

template 行告诉 Ember 我们想要如何插入该组件。它与你在 handlebars 模板中放置该组件时使用的标记完全相同,因此你应该对此很熟悉:

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

请注意,它将 testSnack 作为 snack 参数传递。这是在 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 個讚