block includes
include ../_util-fns
- var _JavaScript = 'JavaScript';
//- Double underscore means don't escape var, use !{__var}.
- var __chaining_op = ';
or ,
';
- var __new_op = 'new
';
- var __objectAsMap = 'object';
:marked
This chapter offers tips and techniques for testing Angular applications.
Along the way you will learn some general testing principles and techniques but the focus is on
testing applications written with Angular
本章提供了一些测试Angular应用的提示和技巧。虽然这里讲述了一些常规测试理念和技巧,但是其重点是测试用Angular编写的应用。
#top
:marked
# Table of Contents
# 目录
1. [Introduction to Angular Testing](#testing-intro)
1. [Angular测试入门](#testing-intro)
1. [Setup](#setup)
1. [搭建测试环境](#setup)
- [setup files](#setup-files): `karma.conf`, `karma-test-shim`, `systemjs.config`
- [文件配置](#setup-files): `karma.conf`, `karma-test-shim`, `systemjs.config`
- [npm packages](#npm-packages)
- [npm 包](#npm-packages)
1. [The first karma test](#1st-karma-test)
1. [第一个Karma测试程序](#1st-karma-test)
1. [Introduction to the Angular testing utilities](#atu-intro)
1. [Angular测试工具](#atu-intro)
1. [The sample application and its tests](#sample-app)
1. [例子应用及其测试](#sample-app)
1. [A simple component test](#simple-component-test)
1. [简单的组件测试程序](#simple-component-test)
- [_configureTestingModule_](#configure-testing-module)
- [_configureTestingModule_](#configure-testing-module)
- [_createComponent_](#create-component)
- [_createComponent_](#create-component)
- [_ComponentFixture_, _DebugElement_, _query(By.css)_](#component-fixture)
- [_ComponentFixture_, _DebugElement_, _query(By.css)_](#component-fixture)
- [_detectChanges_](#detect-changes)
- [_detectChanges_](#detect-changes)
- [_autoDetectChanges_](#auto-detect-changes)
- [_autoDetectChanges_](#auto-detect-changes)
1. [Test a component with a service dependency](#component-with-dependency)
1. [测试拥有服务依赖的组件](#component-with-dependency)
- [test doubles](#service-test-doubles)
- [测试复制品](#service-test-doubles)
- [get the injected service](#get-injected-service)
- [获取注入的服务](#get-injected-service)
- [_TestBed.get_](#testbed-get)
- [_TestBed.get_](#testbed-get)
1. [Test a component with an async service](#component-with-async-service)
1. [测试拥有异步服务的组件](#component-with-async-service)
- [spies](#service-spy)
- [spies](#service-spy)
- [_async_](#async)
- [_async_](#async)
- [_whenStable_](#when-stable)
- [_whenStable_](#when-stable)
- [_fakeAsync_](#async)
- [_fakeAsync_](#async)
- [_tick_](#tick)
- [_tick_](#tick)
- [_jasmine.done_](#jasmine-done)
- [_jasmine.done_](#jasmine-done)
1. [Test a component with an external template](#component-with-external-template)
1. [测试拥有外部模板的组件](#component-with-external-template)
- [_async_](#async-in-before-each) in `beforeEach`
- [_async_](#async-in-before-each) in `beforeEach`
- [_compileComponents_](#compile-components)
- [_compileComponents_](#compile-components)
1. [Test a component with inputs and outputs](#component-with-input-output)
1. [测试拥有导入inputs和导出outputs的组件](#component-with-input-output)
- [_triggerEventHandler_](#trigger-event-handler)
- [_triggerEventHandler_](#trigger-event-handler)
1. [Test a component inside a test host component](#component-inside-test-host)
1. [在宿主组件中测试组件](#component-inside-test-host)
1. [Test a routed component](#routed-component)
1. [测试带路由器的组件](#routed-component)
- [_inject_](#inject)
- [_inject_](#inject)
1. [Test a routed component with parameters](#routed-component-w-param)
1. [测试带有路由和路由参数的组件](#routed-component-w-param)
- [_Observable_ test double](#stub-observable)
- [**可观察**测试复制品](#stub-observable)
1. [Use a _page_ object to simplify setup](#page-object)
1. [使用**page**对象来简化配置](#page-object)
1. [Setup with module imports](#import-module)
1. [用模块的导入进行配置](#import-module)
1. [Override component providers](#component-override)
1. [重载组件提供商](#component-override)
1. [Test a _RouterOutlet_ component](#router-outlet-component)
1. [测试带有**RouterOutlet**组件](#router-outlet-component)
- [stubbing unneeded components](#stub-component)
- [模拟不需要的组件](#stub-component)
- [Stubbing the _RouterLink_](#router-link-stub)
- [模拟_RouterLink_](#router-link-stub)
- [_By.directive_ and injected directives](#by-directive)
- [_By.directive_和注入的指令](#by-directive)
1. ["Shallow" component tests with *NO\_ERRORS\_SCHEMA*](#shallow-component-test)
1. [使用*NO\_ERRORS\_SCHEMA*来“浅化”组件测试程序](#shallow-component-test)
1. [Test an attribute directive](#attribute-directive)
1. [测试属性指令](#attribute-directive)
1. [Isolated unit tests](#isolated-unit-tests "Unit testing without the Angular testing utilities")
1. [孤立的单元测试](#isolated-unit-tests "Unit testing without the Angular testing utilities")
- [Services](#isolated-service-tests)
- [服务](#isolated-service-tests)
- [Pipes](#isolated-pipe-tests)
- [管道](#isolated-pipe-tests)
- [Components](#isolated-component-tests)
- [组件](#isolated-component-tests)
1. [Angular testing utility APIs](#atu-apis)
1. [Angular测试工具APIs](#atu-apis)
- [Stand-alone functions](#atu-apis): `async`, `fakeAsync`, etc.
- [独立函数](#atu-apis): `async`, `fakeAsync`, etc.
- [_TestBed_](#testbed-class-summary)
- [_TestBed_](#testbed-class-summary)
- [_ComponentFixture_](#component-fixture-api-summary)
- [_ComponentFixture_](#component-fixture-api-summary)
- [_DebugElement_](#debug-element-details)
- [_DebugElement_](#debug-element-details)
1. [FAQ](#faq "Frequently asked questions")
1. [常见问题](#faq "Frequently asked questions")
:marked
It’s a big agenda. Fortunately, you can learn a little bit at a time and put each lesson to use.
以上主题繁多。幸运的是,你可以慢慢地阅读并立刻应用每一个主题。
## Live examples
## 在线例子
The chapter sample code is available as live examples for inspection, experiment, and download.
本章所有例子代码都在下面的在线例子中,以供参考、实验和下载。
* karma.conf.js
td
:marked
The karma configuration file that specifies which plug-ins to use,
which application and test files to load, which browser(s) to use,
and how to report test results.
Karma配置文件。它指定使用哪些插件、加载哪个应用和测试文件、使用哪些浏览器和如何报告测试结果。
It loads three other setup files:
它加载三种配置文件:
* `systemjs.config.js`
* `systemjs.config.extras.js`
* `karma-test-shim.js`
tr
td(style="vertical-align: top") karma-test-shim.js
td
:marked
This shim prepares karma specifically for the Angular test environment
and launches karma itself.
It loads the `systemjs.config.js` file as part of that process.
本垫片为Angular测试环境特别准备Karma,并运行Karma。在这个过程中,它加载`systemjs.config.js`文件。
tr
td(style="vertical-align: top") systemjs.config.js
td
:marked
[SystemJS](https://github.com/systemjs/systemjs/blob/master/README.md)
loads the application and test files.
This script tells SystemJS where to find those files and how to load them.
It's the same version of `systemjs.config.js` used by Setup-based applications.
[SystemJS](https://github.com/systemjs/systemjs/blob/master/README.md)
加载应用和测试文件。本脚本告诉SystemJS去哪儿寻找这些文件,以及如何加载它们。
`systemjs.config.js`的版本和基于[搭建本地开发环境](setup.html)的应用使用的一样。
tr
td(style="vertical-align: top") systemjs.config.extras.js
td
:marked
An optional file that supplements the SystemJS configuration in `systemjs.config.js` with
configuration for the specific needs of the application itself.
一个可有可无的文件,用来配置应用自己特殊的需求,补充`systemjs.config.js`里面的SystemJS配置。
A stock `systemjs.config.js` can't anticipate those needs.
You fill the gaps here.
原装`systemjs.config.js`无法预测这些需求。你可以在这里填补空白。
The sample version for this chapter adds the **model barrel**
to the SystemJs `packages` configuration.
本章例子添加了**模型封装桶**到SystemJS的`packages`配置。
tr
td(colspan="2")
+makeExample('testing/ts/systemjs.config.extras.js', '', 'systemjs.config.extras.js')(format='.')
:marked
### npm packages
### npm包
The sample tests are written to run in Jasmine and karma.
The two "fast path" setups added the appropriate Jasmine and karma npm packages to the
`devDependencies` section of the `package.json`.
They were installed when you ran `npm install`.
例子中的测试程序是按照能在`Jasmine`和`Karma`中运行的规格编写的。以上两种“快速途径”配置测试环境,都在`package.json`的`devDependencies`中添加了合适的`Jasmine`和`karma`的`npm`包。
你运行`npm install`时就会安装它们。
.l-hr
#1st-karma-test
:marked
## The first karma test
## 第一个`karma`测试
Start with a simple test to make sure the setup works properly.
编写简单的测试程序,来确认以上的配置是否工作正常。
Create a new file called `1st.spec.ts` in the application root folder, `app/`
在应用的根目录`app/`创建新文件,名叫`1st.spec.ts`。
.alert.is-important
:marked
Tests written in Jasmine are called _specs_ .
**The filename extension must be `.spec.ts`**,
the convention adhered to by `karma.conf.js` and other tooling.
用Jasmine编写的测试程序都被叫做**specs**。**文件名后缀必须是`.spec.ts`**,这是`karma.conf.js`和其它工具所坚持和遵守的规约。
:marked
**Put spec files somewhere within the `app/` folder.**
The `karma.conf.js` tells karma to look for spec files there,
for reasons explained [below](#q-spec-file-location).
**将测试程序spec放到`app/`文件夹下的任何位置。**
`karma.conf.js`告诉`Karma`在这个文件夹中寻找测试程序spec文件,原因在 [这里](#spec-file-location) 有所解释。
Add the following code to `app/1st.spec.ts`.
添加下面的代码到`app/1st.spec.ts`。
+makeExample('testing/ts/app/1st.spec.ts', '', 'app/1st.spec.ts')(format='.')
:marked
### Run karma
### 运行Karma
Compile and run it in karma from the command line with this command:
使用下面的命令从命令行中编译并在`Karma`中运行上面的测试程序。
code-example(format="." language="bash").
npm test
:marked
The command compiles the application and test code and starts karma.
Both processes watch pertinent files, write messages to the console, and re-run when they detect changes.
该命令编译应用及其测试代码,并启动Karma。
两个进程都监视相关文件,往控制台输入信息和检测到变化时自动重新运行。
.l-sub-section
:marked
The documentation setup defines the `test` command in the `scripts` section of npm's `package.json`.
The Angular CLI has different commands to do the same thing. Adjust accordingly.
《快速起步》在npm的`package.json`中的`scripts`里定义了`test`命令。
Angular CLI使用不同的命令来做同样的事情。对不同的环境采取不同的方案。
:marked
After a few moments, karma opens a browser and starts writing to the console.
等一小段时间后,Karma便打开浏览器并开始向控制台输出。
figure.image-display
img(src='/resources/images/devguide/testing/karma-browser.png' style="width:400px;" alt="Karma browser")
:marked
Hide (don't close!) the browser and focus on the console output which should look something like this.
隐藏(不要关闭)浏览器,查看控制台的输出,应该看起来像这样:
code-example(format="." language="bash").
> npm test
...
[0] 1:37:03 PM - Compilation complete. Watching for file changes.
...
[1] Chrome 51.0.2704: Executed 0 of 0 SUCCESS
Chrome 51.0.2704: Executed 1 of 1 SUCCESS
SUCCESS (0.005 secs / 0.005 secs)
:marked
Both the compiler and karma continue to run. The compiler output is preceeded by `[0]`;
the karma output by `[1]`.
编译器和`Karma`都会持续运行。编译器的输入信息前面有`[0]`,`Karma`的输出前面有`[1]`。
Change the expectation from `true` to `false`.
将期望从`true`变换为`false`。
The _compiler_ watcher detects the change and recompiles.
**编译器**监视器检测到这个变化并重新编译。
code-example(format="." language="bash").
[0] 1:49:21 PM - File change detected. Starting incremental compilation...
[0] 1:49:25 PM - Compilation complete. Watching for file changes.
:marked
The _karma_ watcher detects the change to the compilation output and re-runs the test.
**`Karma`**监视器检测到编译器输出的变化,并重新运行测试。
code-example(format="." language="bash").
[1] Chrome 51.0.2704 1st tests true is true FAILED
[1] Expected false to equal true.
[1] Chrome 51.0.2704: Executed 1 of 1 (1 FAILED) (0.005 secs / 0.005 secs)
:marked
It failed of course.
正如所料,测试结果是**失败**。
Restore the expectation from `false` back to `true`.
Both processes detect the change, re-run, and karma reports complete success.
将期望从`false`恢复为`true`。两个进程都检测到这个变化,自动重新运行,`Karma`报告测试成功。
.alert.is-helpful
:marked
The console log can be quite long. Keep your eye on the last line.
It says `SUCCESS` when all is well.
控制台的日志可能会非常长。注意最后一样。当一切正常时,它会显示`SUCCESS`。
:marked
### Test debugging
### 调试测试程序
Debug specs in the browser in the same way you debug an application.
在浏览器中,像调试应用一样调试测试程序spec。
- Reveal the karma browser window (hidden earlier).
- 显示`Karma`的浏览器窗口(之前被隐藏了)。
- Click the "DEBUG" button; it opens a new browser tab and re-runs the tests
- 点击“DEBUG”按钮;它打开一页新浏览器标签并重新开始运行测试程序
- Open the browser's “Developer Tools” (F12 or Ctrl-Shift-I).
- 打开浏览器的“Developer Tools”(F12或者Ctrl-Shift-I)。
- Pick the "sources" section
- 选择“sources”页
- Open the `1st.spec.ts` test file (Ctrl-P, then start typing the name of the file).
- 打开`1st.spec.ts`测试文件(Ctrl-P, 然后输入文件名字)。
- Set a breakpoint in the test
- 在测试程序中设置断点。
- Refresh the browser … and it stops at the breakpoint.
- 刷新浏览器...然后它就会停在断点上。
figure.image-display
img(src='/resources/images/devguide/testing/karma-1st-spec-debug.png' style="width:700px;" alt="Karma debugging")
a(href="#top").to-top Back to top
a(href="#top").to-top 回到顶部
.l-hr
#atu-intro
:marked
## Introduction to the Angular Testing Utilities
## Angular测试工具入门
Many tests explore how applications classes interact with Angular and the DOM while under Angular's control.
许多测试程序探索应用的类在被`Angular`控制时,是如何与`Angular`和`DOM`互动的。
Such tests are easy to write with the help of the Angular testing utilities
which include the `TestBed` class and some helper functions.
Angular测试工具包含了`TestBed`类和一些辅助函数方法,在它们的帮助下,很容易编写上面那样的测试程序。
Tests written with these utilities are the main focus of this chapter.
But they are not the only tests you should write.
利用**这些工具**编写的测试程序是本章的主要焦点。但是它们不是你能写的唯一测试类型。
### Isolated unit tests
### 孤立的单元测试
[Isolated unit tests](#isolated-unit-tests "Unit testing without the Angular testing utilities")
examine an instance of a class all by itself without any dependence on Angular or any injected values.
The tester creates a test instance of the class with new, supplying test doubles for the constructor parameters as needed, and
then probes the test instance API surface.
[孤立的单元测试](#isolated-unit-tests "不使用Angular测试工具进行单元测试")独立自己检测类的实例,不依靠Angular或者任何其它注入值。
测试器使用`new`创建类的测试实例,在需要时提供用于测试的构造函数参数复制品,并测试被测试实例的API。
You can and should write isolated unit tests for pipes and services.
你可以,也应该为服务和管道编写孤立的单元测试。
+makeExample('testing/ts/app/shared/title-case.pipe.spec.ts', 'mini-excerpt', 'app/shared/title-case.pipe.spec.ts (excerpt)')
:marked
Components can be tested in isolation as well.
However, isolated unit tests don't reveal how these classes interact with Angular.
In particular, they can't reveal how a component class interacts with its own template or with other components.
Such tests require the Angular testing utilities.
孤立的测试不会展示类是如何与Angular互动的。也就是说,它们不会展示组件的类是如何与自己的模板或者其它组件互动的。
这样的测试程序需要Angular测试工具。
### Testing with the Angular Testing Utilities
### 利用**Angular测试工具**进行测试
The Angular testing utilities include the `TestBed` class and several helper functions from `@angular/core/testing`.
**Angular测试工具**包含了`TestBed`类和在`@angular/core/testing`中一些辅助函数方法。
The `TestBed` creates an Angular testing module — an `@NgModule` class —
that you configure to produce the module environment for the class you want to test.
You tell the `TestBed` to create an instance of the _component-under-test_ and probe that instance with tests.
`TestBed`创建Angular测试模块 - `@NgModule`类 - 通过配置它,你为想要测试的类创造模块环境。
通过`TestBed`创建被测试的组件的实例,并使用测试程序来测探这个实例。
Before each spec, the `TestBed` resets itself to a base state.
The base state includes a default testing module configuration consisting of the
declarables (components, directives, and pipes) and providers (some of them mocked)
that almost everyone needs.
在每个spec之前,`TestBed`将自己重设为初始状态。
这个初始状态包含了一套默认的、几乎所有情况都需要的测试模块配置,包括可声明类(组件、指令和管道)和提供商(其中一些是伪造的)。
.l-sub-section
:marked
The testing shims mentioned [earlier](#setup) initialize the testing module configuration
to something like the `BrowserModule` from `@angular/platform-browser`.
[之前](#setup)提到的测试垫片初始化测试模块配置到一个模块,这个模块和`@angular/platform-browser`中的`BrowserModule`类似。
:marked
This default configuration is merely a _foundation_ for testing an app.
You call `TestBed.configureTestingModule` with an object that defines additional imports, declarations, providers and schemas
to fit your application tests.
Optional `override...` methods can fine-tune aspects of the configuration.
默认配置只是测试应用的**基础**。
在`TestBed.configureTestingModule`中定义额外imports、declarations、providers和schemas的对象,构建适合你的应用程序的测试环境。
可选的`override...`方法可以微调配置的各个方面。
After configuring the `TestBed`, tell it to create an instance of the _component-under-test_ and the test fixture
that you'll need to inspect and control the component's immediate environment.
`TestBed`配置完成以后,用它创建**被测试的组件**的实例和测试fixture,我们可以用它们检查和控制组件周围的环境。
+makeExample('testing/ts/app/banner.component.spec.ts', 'simple-example-before-each', 'app/banner.component.spec.ts (simplified)')(format='.')
:marked
Angular tests can interact with the HTML in the test DOM,
simulate user activity, tell Angular to perform specific task (such as change detection),
and see the effects of these actions both in the _component-under-test_ and in the test DOM.
Angular测试可以在测试DOM中与HTML互动,模拟用户行为,让Angular执行特定任务(比如变换检测),并在被测试的组件和测试DOM中查看这些行为的效果。
+makeExample('testing/ts/app/banner.component.spec.ts', 'simple-example-it', 'app/banner.component.spec.ts (simplified)')(format='.')
:marked
A comprehensive review of the Angular testing utilities appears [later in the chapter](#atu-apis).
Let's dive right into Angular testing, starting with the components of a sample application.
关于Angular测试工具的完整回顾将会在[本章后面](#atu-apis)出现。
现在开始深入到Angular测试,让我们以例子应用的组件开始。
a(href="#top").to-top Back to top
a(href="#top").to-top 回到顶部
.l-hr
#sample-app
:marked
## The sample application and its tests
## 例子应用和它的测试程序
This chapter tests a cut-down version of the _Tour of Heroes_ [tutorial app](../tutorial).
本章测试了**简化版本的英雄指南**[教程应用程序](../tutorial)。
The following live example shows how it works and provides the complete source code.
下面的在线例子展示了它是如何工作的,并提供了完整的源代码。
:marked
The following live example runs all the tests of this application
inside the browser, using the Jasmine Test Runner instead of karma.
下面的在线例子在浏览器中运行该应用的所有测试程序,使用的是`Jasmine`测试运行器,而非`Karma`。
It includes the tests discussed in this chapter and additional tests for you to explore.
This live example contains both application and test code.
Give it some time to load and warm up.
它包含了本章讨论的测试程序和其它测试程序。本在线例子包含了整个应用和测试代码。给它一些时间来加载。