Unit tests are generally used to test a small piece of code and ensure that it is doing what was intended. Unlike integration tests, they are narrow in scope and do not require the Ember application to be running.

单元测试用于测试代码的一个小片段,确保其功能正常。与集成测试不同,单元测试被限定在一个范围内,并且不需要Ember应用运行。

Globals vs Modules

全局 vs 模块

In the past, it has been difficult to test portions of your Ember application without loading the entire app as a global. By having your application written using modules (CommonJS, AMD, etc), you are able to require just code that is to be tested without having to pluck the pieces out of your global application.

过去如果没有作为一个全局变量加载整个Ember应用,要对应用进行测试非常困难。通过使用模块(CommonJSAMD等)来编写应用,可以只加载被测试的部分,而不用将其从全局的应用中抽出来测试。

Unit Testing Helpers

单元测试助手

Ember-QUnit is the default unit testing helper suite for Ember. It can and should be used as a template for other test framework helpers. It uses your application’s resolver to find and automatically create test subjects for you using the moduleFor and test helpers.

Ember-QUnit是Ember的缺省的单元测试助手套件。其可以作为其他测试框架助手的样板来使用。Ember-QUnit使用应用的resolver来查找并使用moduleFortest助手自动创建被测主体。

A test subject is simply an instance of the object that a particular test is making assertions about. Usually test subjects are manually created by the writer of the test.

测试主体是一个特定测试将围绕其进行断言的一个简单对象的实例。通常测试主体有测试者手动创建。

The unit testing section of this guide will use the Ember-QUnit library, but the concepts and examples should translate easily to other frameworks.

本指南中的单元测试将采用Ember-QUnit来完成,不过其中的概念和例子可以非常容易的迁移至其他的框架。

Available Helpers

可用的助手

By including Ember-QUnit, you will have access to a number of test helpers.

通过加入Ember-QUnit,可以获取一系列测试助手。

  • moduleFor(fullName [, description [, callbacks]])

    • fullName: The full name of the unit, (ie. controller:application, route:index, etc.)
    • description: the description of the module
    • callbacks: normal QUnit callbacks (setup and teardown), with addition to needs, which allows you specify the other units the tests will need.

    • fullName: 单元测试全名。(例如:controller:applicationroute:index等。)

    • description: 模块描述。
    • callbacks: 完成附加需求的QUnit回调(setupteardown),可以通过回调来指定测试需要的其他单元)。
  • moduleForComponent(name [, description [, callbacks]])

    • name: the short name of the component that you’d use in a template, (ie. x-foo, ic-tabs, etc.)
    • description: the description of the module
    • callbacks: normal QUnit callbacks (setup and teardown), with addition to needs, which allows you specify the other units the tests will need.

    • name: 将被用于模板中得简短组件名。(例如:x-fooic-tabs等等。)

    • description: 模块描述。
    • callbacks: 完成附加需求的QUnit回调(setupteardown),可以通过回调来指定测试需要的其他单元)。
  • moduleForModel(fullName [, description [, callbacks]])

    • name: the short name of the model you’d use in store operations (ie. user, assignmentGroup, etc.)
    • description: the description of the module
    • callbacks: normal QUnit callbacks (setup and teardown), with addition to needs, which allows you specify the other units the tests will need.

    • name: 在store操作中将使用的简短模型名。(例如:userassignmentGroup等。)

    • description: 模块描述。
    • callbacks: 完成附加需求的QUnit回调(setupteardown),可以通过回调来指定测试需要的其他单元)。
  • test

    • Same as QUnit test except it includes the subject function which is used to create the test subject.

    • 与QUnit的test期望一样,其包含了用来创建测试主体的subject函数。 to create the test subject.

  • setResolver

    • Sets the resolver which will be used to lookup objects from the application container.
  • 设置用来从应用容器中查找对象的resolver

Unit Testing Setup

设置单元测试

In order to unit test your Ember application, you need to let Ember know it is in test mode. To do so, you must call Ember.setupForTesting().

为了对Ember应用进行单元测试,首先需要让Ember知道其在测试模式。为实现这个目的,需要调用Ember.setupForTesting()

  1. Ember.setupForTesting();

The setupForTesting() function call makes ember turn off its automatic run loop execution. This gives us an ability to control the flow of the run loop ourselves, to a degree. Its default behaviour of resolving all promises and completing all async behaviour are suspended to give you a chance to set up state and make assertions in a known state. In other words, you know that if you run “visit” to get to a particular URL, you can be sure the URL has been visited and that’s the only behaviour that has transpired. If we didn’t use this mode, our assertions would most likely be executed before the async behaviour had taken place, so our assertion results would be unpredictable.

setupForTesting()函数的调用通知Ember关闭了其自动运行循环的执行。这样使得可以能够自己一定程度上控制运行循环流程。缺省的履行所有承诺和完成所有异步行为的行为被暂停,使得可以在一个已知的状态来作出断言。换句话说,如果已知运行visit到一个特定的URL,就可以肯定URL被访问并且也是唯一发生的行为。如果并没有采用这种方式,那么断言很可能会在异步行为发生之前就被执行了,以至于断言结果并不是可预知。

With a module-based application, you have access to the unit test helpers simply by requiring the exports of the module. However, if you are testing a global Ember application, you are still able to use the unit test helpers. Instead of importing the ember-qunit module, you need to make the unit test helpers global with emq.globalize():

在一个基于模块的应用里,可以通过请求模块的导出来访问单元测试助手。然而,如果在测试一个全局的Ember应用,一样可以使用单元测试助手。作为导入ember-qunit模块的替代方案,需要通过emq.globalize()来使得单元测试变成全局的。

  1. emq.globalize();

This will make the above helpers available globally.

这就使得上述的助手变成了全局可用。

The Resolver

解析器

The Ember resolver plays a huge role when unit testing your application. It provides the lookup functionality based on name, such as route:index or model:post.

Ember解析器在对应用进行单元测试的时候扮演了一个非常重要的角色。其提供了一个基于名字查找的功能,例如route:index或者model:post

If you do not have a custom resolver or are testing a global Ember application, the resolver should be set like this:

如果没有一个自定义的解析器,或者测试一个全局的Ember应用,解析器应该进行如下的设置:

Make sure to replace “App” with your application’s namespace in the following line

确定使用应用的命名空间来替代下面一行代码中得App

  1. setResolver(Ember.DefaultResolver.create({ namespace: App })

Otherwise, you would require the custom resolver and pass it to setResolver like this (ES6 example):

否则,需要获取自定义解析器,并将其传递给setResolver,就如(ES6示例)中一般:

  1. import Resolver from './path/to/resolver';
  2. import { setResolver } from 'ember-qunit';
  3. setResolver(Resolver.create());