fix: 翻译完了《测试》的剩余部分

This commit is contained in:
Zhicheng Wang 2018-03-15 15:48:26 +08:00 committed by Zhicheng Wang
parent 6d5cfd568b
commit cae70fab87

View File

@ -2971,14 +2971,21 @@ Angular 编译器会为 `<app-banner>` 元素创建 `BannerComponentStub`,并
### Components with _RouterLink_ ### Components with _RouterLink_
### 带有 `RouterLink` 的组件
The real `RouterLinkDirective` is quite complicated and entangled with other components The real `RouterLinkDirective` is quite complicated and entangled with other components
and directives of the `RouterModule`. and directives of the `RouterModule`.
It requires challenging setup to mock and use in tests. It requires challenging setup to mock and use in tests.
真实的 `RouterLinkDirective` 太复杂了,而且与 `RouterModule` 中的其它组件和指令有着千丝万缕的联系。
要在设置阶段 Mock 它以及在测试中使用它具有一定的挑战性。
The `RouterLinkDirectiveStub` in this sample code replaces the real directive The `RouterLinkDirectiveStub` in this sample code replaces the real directive
with an alternative version designed to validate the kind of anchor tag wiring with an alternative version designed to validate the kind of anchor tag wiring
seen in the `AppComponent` template. seen in the `AppComponent` template.
这段范例代码中的 `RouterLinkDirectiveStub` 用一个代用品替换了真实的指令,这个代用品用来验证 `AppComponent` 中所用链接的类型。
<code-example <code-example
path="testing/src/testing/router-link-directive-stub.ts" path="testing/src/testing/router-link-directive-stub.ts"
region="router-link" region="router-link"
@ -2988,19 +2995,28 @@ seen in the `AppComponent` template.
The URL bound to the `[routerLink]` attribute flows in to the directive's `linkParams` property. The URL bound to the `[routerLink]` attribute flows in to the directive's `linkParams` property.
这个 URL 被绑定到了 `[routerLink]` 属性,它的值流入了该指令的 `linkParams` 属性。
The `host` metadata property wires the click event of the host element The `host` metadata property wires the click event of the host element
(the `<a>` anchor elements in `AppComponent`) to the stub directive's `onClick` method. (the `<a>` anchor elements in `AppComponent`) to the stub directive's `onClick` method.
它的元数据中的 `host` 属性把宿主元素(即 `AppComponent` 中的 `<a>` 元素)的 `click` 事件关联到了这个桩指令的 `onClick` 方法。
Clicking the anchor should trigger the `onClick()` method, Clicking the anchor should trigger the `onClick()` method,
which sets the stub's telltale `navigatedTo` property. which sets the stub's telltale `navigatedTo` property.
Tests inspect `navigatedTo` to confirm that clicking the anchor Tests inspect `navigatedTo` to confirm that clicking the anchor
set the expected route definition. set the expected route definition.
点击这个链接应该触发 `onClick()` 方法,其中会设置该桩指令中的警示器属性 `navigatedTo`
测试中检查 `navigatedTo` 以确认点击该链接确实如预期的那样根据路由定义设置了该属性。
<div class="l-sub-section"> <div class="l-sub-section">
Whether the router is configured properly to navigate with that route definition is a Whether the router is configured properly to navigate with that route definition is a
question for a separate set of tests. question for a separate set of tests.
路由器的配置是否正确和是否能按照那些路由定义进行导航,是测试中一组独立的问题。
</div> </div>
{@a by-directive} {@a by-directive}
@ -3009,6 +3025,8 @@ question for a separate set of tests.
#### _By.directive_ and injected directives #### _By.directive_ and injected directives
#### `By.directive` 与注入的指令
A little more setup triggers the initial data binding and gets references to the navigation links: A little more setup triggers the initial data binding and gets references to the navigation links:
再一步配置触发了数据绑定的初始化,获取导航链接的引用: 再一步配置触发了数据绑定的初始化,获取导航链接的引用:
@ -3022,15 +3040,25 @@ A little more setup triggers the initial data binding and gets references to the
Three points of special interest: Three points of special interest:
有三点特别重要:
1. You can locate the anchor elements with an attached directive using `By.directive`. 1. You can locate the anchor elements with an attached directive using `By.directive`.
你可以使用 `By.directive` 来定位一个带附属指令的链接元素。
1. The query returns `DebugElement` wrappers around the matching elements. 1. The query returns `DebugElement` wrappers around the matching elements.
该查询返回包含了匹配元素的 `DebugElement` 包装器。
1. Each `DebugElement` exposes a dependency injector with the 1. Each `DebugElement` exposes a dependency injector with the
specific instance of the directive attached to that element. specific instance of the directive attached to that element.
每个 `DebugElement` 都会导出该元素中的一个依赖注入器,其中带有指定的指令实例。
The `AppComponent` links to validate are as follows: The `AppComponent` links to validate are as follows:
`AppComponent` 中要验证的链接如下:
<code-example <code-example
path="testing/src/app/app.component.html" path="testing/src/app/app.component.html"
region="links" region="links"
@ -3043,6 +3071,8 @@ The `AppComponent` links to validate are as follows:
Here are some tests that confirm those links are wired to the `routerLink` directives Here are some tests that confirm those links are wired to the `routerLink` directives
as expected: as expected:
下面这些测试用来确认那些链接是否如预期般连接到了 `RouterLink` 指令中:
<code-example path="testing/src/app/app.component.spec.ts" region="tests" title="app/app.component.spec.ts (selected tests)" linenums="false"></code-example> <code-example path="testing/src/app/app.component.spec.ts" region="tests" title="app/app.component.spec.ts (selected tests)" linenums="false"></code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -3051,6 +3081,10 @@ The "click" test _in this example_ is misleading.
It tests the `RouterLinkDirectiveStub` rather than the _component_. It tests the `RouterLinkDirectiveStub` rather than the _component_.
This is a common failing of directive stubs. This is a common failing of directive stubs.
其实*这个例子中*的“click”测试误入歧途了。
它测试的重点其实是 `RouterLinkDirectiveStub` ,而不是该组件。
这是写桩指令时常见的错误。
It has a legitimate purpose in this guide. It has a legitimate purpose in this guide.
It demonstrates how to find a `RouterLink` element, click it, and inspect a result, It demonstrates how to find a `RouterLink` element, click it, and inspect a result,
without engaging the full router machinery. without engaging the full router machinery.
@ -3067,12 +3101,14 @@ re-calculates parameters, or re-arranges navigation options when the user clicks
#### What good are these tests? #### What good are these tests?
#### 这些测试有什么优点?
Stubbed `RouterLink` tests can confirm that a component with links and an outlet is setup properly, Stubbed `RouterLink` tests can confirm that a component with links and an outlet is setup properly,
that the component has the links it should have, and that they are all pointing in the expected direction. that the component has the links it should have, and that they are all pointing in the expected direction.
These tests do not concern whether the app will succeed in navigating to the target component when the user clicks a link. These tests do not concern whether the app will succeed in navigating to the target component when the user clicks a link.
stub伪造的`RouterLink`测试可以确认带有链接和outlet的组件的设置的正确性确认组件有应该有的链接确认它们都指向了正确的方向。 `RouterLink` 的桩指令进行测试可以确认带有链接和outlet的组件的设置的正确性确认组件有应该有的链接确认它们都指向了正确的方向。
这些测试程序不关心用户点击链接时,应用是否会成功的导航到目标组件。 这些测试程序不关心用户点击链接时,也不关心应用是否会成功的导航到目标组件。
Stubbing the RouterLink and RouterOutlet is the best option for such limited testing goals. Stubbing the RouterLink and RouterOutlet is the best option for such limited testing goals.
Relying on the real router would make them brittle. Relying on the real router would make them brittle.
@ -3080,7 +3116,7 @@ They could fail for reasons unrelated to the component.
For example, a navigation guard could prevent an unauthorized user from visiting the `HeroListComponent`. For example, a navigation guard could prevent an unauthorized user from visiting the `HeroListComponent`.
That's not the fault of the `AppComponent` and no change to that component could cure the failed test. That's not the fault of the `AppComponent` and no change to that component could cure the failed test.
对于这样局限的测试目标stub伪造RouterLink和RouterOutlet是最佳选择。 对于这些有限的测试目标,使用 RouterLink 桩指令和 RouterOutlet 桩组件 是最佳选择。
依靠真正的路由器会让它们很脆弱。 依靠真正的路由器会让它们很脆弱。
它们可能因为与组件无关的原因而失败。 它们可能因为与组件无关的原因而失败。
例如,一个导航守卫可能防止没有授权的用户访问`HeroListComponent` 例如,一个导航守卫可能防止没有授权的用户访问`HeroListComponent`
@ -3096,7 +3132,7 @@ in the presence of conditions that influence guards such as whether the user is
A future guide update will explain how to write such A future guide update will explain how to write such
tests with the `RouterTestingModule`. tests with the `RouterTestingModule`.
未来本章的更新将介绍如何使用`RouterTestingModule`来编写这样的测试程序。 未来本章的更新将介绍如何使用 `RouterTestingModule` 来编写这样的测试程序。
</div> </div>
@ -3106,6 +3142,8 @@ tests with the `RouterTestingModule`.
### Use a _page_ object ### Use a _page_ object
### 使用页面page对象
The `HeroDetailComponent` is a simple view with a title, two hero fields, and two buttons. The `HeroDetailComponent` is a simple view with a title, two hero fields, and two buttons.
`HeroDetailComponent`是带有标题、两个英雄字段和两个按钮的简单视图。 `HeroDetailComponent`是带有标题、两个英雄字段和两个按钮的简单视图。
@ -3116,6 +3154,8 @@ The `HeroDetailComponent` is a simple view with a title, two hero fields, and tw
But there's plenty of template complexity even in this simple form. But there's plenty of template complexity even in this simple form.
但即使是这么简单的表单,其模板中也涉及到不少复杂性。
<code-example <code-example
path="testing/src/app/hero/hero-detail.component.html" title="app/hero/hero-detail.component.html" linenums="false"> path="testing/src/app/hero/hero-detail.component.html" title="app/hero/hero-detail.component.html" linenums="false">
@ -3123,16 +3163,28 @@ But there's plenty of template complexity even in this simple form.
Tests that exercise the component need ... Tests that exercise the component need ...
这些供练习用的组件需要 ……
* to wait until a hero arrives before elements appear in the DOM. * to wait until a hero arrives before elements appear in the DOM.
等获取到英雄之后才能让元素出现在 DOM 中。
* a reference to the title text. * a reference to the title text.
一个对标题文本的引用。
* a reference to the name input box to inspect and set it. * a reference to the name input box to inspect and set it.
一个对 name 输入框的引用,以便对它进行探查和修改。
* references to the two buttons so they can click them. * references to the two buttons so they can click them.
引用两个按钮,以便点击它们。
* spies for some of the component and router methods. * spies for some of the component and router methods.
为组件和路由器的方法安插间谍。
Even a small form such as this one can produce a mess of tortured conditional setup and CSS element selection. Even a small form such as this one can produce a mess of tortured conditional setup and CSS element selection.
即使是像这样一个很小的表单也能产生令人疯狂的错综复杂的条件设置和CSS元素选择。 即使是像这样一个很小的表单也能产生令人疯狂的错综复杂的条件设置和CSS元素选择。
@ -3140,8 +3192,12 @@ Even a small form such as this one can produce a mess of tortured conditional se
Tame the complexity with a `Page` class that handles access to component properties Tame the complexity with a `Page` class that handles access to component properties
and encapsulates the logic that sets them. and encapsulates the logic that sets them.
可以使用 `Page` 类来征服这种复杂性。`Page` 类可以处理对组件属性的访问,并对设置这些属性的逻辑进行封装。
Here is such a `Page` class for the `hero-detail.component.spec.ts` Here is such a `Page` class for the `hero-detail.component.spec.ts`
下面是一个供 `hero-detail.component.spec.ts` 使用的 `Page`
<code-example <code-example
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="page" region="page"
@ -3168,8 +3224,13 @@ The [_HeroDetailComponent_ tests](#tests-w-test-double) in an earlier section de
keep the tests short and _on message_. keep the tests short and _on message_.
There are no distractions: no waiting for promises to resolve and no searching the DOM for element values to compare. There are no distractions: no waiting for promises to resolve and no searching the DOM for element values to compare.
前面小节中的 [`HeroDetailComponent` 测试](#tests-w-test-double)示范了如何 `createComponent`,而 `page` 让这些测试保持简短而富有表达力。
而且还不用分心:不用等待承诺被解析,不必在 DOM 中找出元素的值才能进行比较。
Here are a few more `HeroDetailComponent` tests to reinforce the point. Here are a few more `HeroDetailComponent` tests to reinforce the point.
还有更多的 `HeroDetailComponent` 测试可以证明这一点。
<code-example <code-example
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="selected-tests" region="selected-tests"
@ -3183,15 +3244,21 @@ Here are a few more `HeroDetailComponent` tests to reinforce the point.
### Calling _compileComponents()_ ### Calling _compileComponents()_
### 调用 `compileComponents()`
<div class="alert is-helpful"> <div class="alert is-helpful">
You can ignore this section if you _only_ run tests with the CLI `ng test` command You can ignore this section if you _only_ run tests with the CLI `ng test` command
because the CLI compiles the application before running the tests. because the CLI compiles the application before running the tests.
如果你*只想*使用 CLI 的 `ng test` 命令来运行测试,那么可以忽略这一节。
</div> </div>
If you run tests in a **non-CLI environment**, the tests may fail with a message like this one: If you run tests in a **non-CLI environment**, the tests may fail with a message like this one:
如果你在**非 CLI 环境**中运行测试,这些测试可能会报错,错误信息如下:
<code-example language="sh" class="code-shell" hideCopy> <code-example language="sh" class="code-shell" hideCopy>
Error: This test module uses the component BannerComponent Error: This test module uses the component BannerComponent
@ -3204,6 +3271,8 @@ The root of the problem is at least one of the components involved in the test
specifies an external template or CSS file as specifies an external template or CSS file as
the following version of the `BannerComponent` does. the following version of the `BannerComponent` does.
问题的根源在于这个测试中至少有一个组件引用了外部模板或外部 CSS 文件,就像下面这个 `BannerComponent` 所示:
<code-example <code-example
path="testing/src/app/banner/banner-external.component.ts" path="testing/src/app/banner/banner-external.component.ts"
title="app/banner/banner-external.component.ts (external template & css)" linenums="false"> title="app/banner/banner-external.component.ts (external template & css)" linenums="false">
@ -3212,6 +3281,8 @@ the following version of the `BannerComponent` does.
The test fails when the `TestBed` tries to create the component. The test fails when the `TestBed` tries to create the component.
`TestBed` 视图创建组件时,这个测试失败了:
<code-example <code-example
path="testing/src/app/banner/banner.component.spec.ts" path="testing/src/app/banner/banner.component.spec.ts"
region="configure-and-create" region="configure-and-create"
@ -3223,26 +3294,42 @@ The test fails when the `TestBed` tries to create the component.
Recall that the app hasn't been compiled. Recall that the app hasn't been compiled.
So when you call `createComponent()`, the `TestBed` compiles implicitly. So when you call `createComponent()`, the `TestBed` compiles implicitly.
回想一下,这个应用从未编译过。
所以当你调用 `createComponent()` 的时候,`TestBed` 就会进行隐式编译。
That's not a problem when the source code is in memory. That's not a problem when the source code is in memory.
But the `BannerComponent` requires external files But the `BannerComponent` requires external files
that the compile must read from the file system, that the compile must read from the file system,
an inherently _asynchronous_ operation. an inherently _asynchronous_ operation.
当它的源码都在内存中的时候,这样做没问题。
不过 `BannerComponent` 需要一些外部文件,编译时必须从文件系统中读取它,而这是一个天生的*异步*操作。
If the `TestBed` were allowed to continue, the tests would run and fail mysteriously If the `TestBed` were allowed to continue, the tests would run and fail mysteriously
before the compiler could finished. before the compiler could finished.
如果 `TestBed` 继续执行,这些测试就会继续运行,并在编译器完成这些异步工作之前导致莫名其妙的失败。
The preemptive error message tells you to compile explicitly with `compileComponents()`. The preemptive error message tells you to compile explicitly with `compileComponents()`.
这些错误信息告诉你要使用 `compileComponents()` 进行显式的编译。
#### _compileComponents()_ is async #### _compileComponents()_ is async
#### `compileComponents()` 是异步的
You must call `compileComponents()` within an asynchronous test function. You must call `compileComponents()` within an asynchronous test function.
你必须在异步测试函数中调用 `compileComponents()`
<div class="alert is-critical"> <div class="alert is-critical">
If you neglect to make the test function async If you neglect to make the test function async
(e.g., forget to use `async()` as described below), (e.g., forget to use `async()` as described below),
you'll see this error message you'll see this error message
如果你忘了把测试函数标为异步的(比如忘了像稍后的代码中那样使用 `async()`),就会看到下列错误。
<code-example language="sh" class="code-shell" hideCopy> <code-example language="sh" class="code-shell" hideCopy>
Error: ViewDestroyedError: Attempt to use a destroyed view Error: ViewDestroyedError: Attempt to use a destroyed view
@ -3253,12 +3340,20 @@ Error: ViewDestroyedError: Attempt to use a destroyed view
A typical approach is to divide the setup logic into two separate `beforeEach()` functions: A typical approach is to divide the setup logic into two separate `beforeEach()` functions:
典型的做法是把设置逻辑拆成两个独立的 `beforeEach()` 函数:
1. An async `beforeEach()` that compiles the components 1. An async `beforeEach()` that compiles the components
异步的 `beforeEach()` 负责编译组件
1. A synchronous `beforeEach()` that performs the remaining setup. 1. A synchronous `beforeEach()` that performs the remaining setup.
同步的 `beforeEach()` 负责执行其余的设置代码。
To follow this pattern, import the `async()` helper with the other testing symbols. To follow this pattern, import the `async()` helper with the other testing symbols.
要想使用这种模式,就要和其它符号一起从测试库中导入 `async()` 辅助函数。
<code-example <code-example
path="testing/src/app/banner/banner-external.component.spec.ts" path="testing/src/app/banner/banner-external.component.spec.ts"
region="import-async"> region="import-async">
@ -3267,8 +3362,12 @@ To follow this pattern, import the `async()` helper with the other testing symbo
#### The async _beforeEach_ #### The async _beforeEach_
#### 异步的 `beforeEach`
Write the first async `beforeEach` like this. Write the first async `beforeEach` like this.
像下面这样编写第一个异步的 `beforeEach`
<code-example <code-example
path="testing/src/app/banner/banner-external.component.spec.ts" path="testing/src/app/banner/banner-external.component.spec.ts"
region="async-before-each" region="async-before-each"
@ -3278,34 +3377,56 @@ Write the first async `beforeEach` like this.
The `async()` helper function takes a parameterless function with the body of the setup. The `async()` helper function takes a parameterless function with the body of the setup.
`async()` 辅助函数接受一个无参函数,其内容是设置代码。
The `TestBed.configureTestingModule()` method returns the `TestBed` class so you can chain The `TestBed.configureTestingModule()` method returns the `TestBed` class so you can chain
calls to other `TestBed` static methods such as `compileComponents()`. calls to other `TestBed` static methods such as `compileComponents()`.
`TestBed.configureTestingModule()` 方法返回 `TestBed` 类,所以你可以链式调用其它 `TestBed` 中的静态方法,比如 `compileComponents()`
In this example, the `BannerComponent` is the only component to compile. In this example, the `BannerComponent` is the only component to compile.
Other examples configure the testing module with multiple components Other examples configure the testing module with multiple components
and may import application modules that hold yet more components. and may import application modules that hold yet more components.
Any of them could be require external files. Any of them could be require external files.
在这个例子中,`BannerComponent` 是仅有的待编译组件。
其它例子中可能会使用多个组件来配置测试模块,并且可能引入某些具有其它组件的应用模块。
它们中的任何一个都可能需要外部文件。
The `TestBed.compileComponents` method asynchronously compiles all components configured in the testing module. The `TestBed.compileComponents` method asynchronously compiles all components configured in the testing module.
`TestBed.compileComponents` 方法会异步编译测试模块中配置过的所有组件。
<div class="alert is-important"> <div class="alert is-important">
Do not re-configure the `TestBed` after calling `compileComponents()`. Do not re-configure the `TestBed` after calling `compileComponents()`.
在调用了 `compileComponents()` 之后就不能再重新配置 `TestBed` 了。
</div> </div>
Calling `compileComponents()` closes the current `TestBed` instance to further configuration. Calling `compileComponents()` closes the current `TestBed` instance to further configuration.
You cannot call any more `TestBed` configuration methods, not `configureTestingModule()` You cannot call any more `TestBed` configuration methods, not `configureTestingModule()`
nor any of the `override...` methods. The `TestBed` throws an error if you try. nor any of the `override...` methods. The `TestBed` throws an error if you try.
调用 `compileComponents()` 会关闭当前的 `TestBed` 实例,不再允许进行配置。
你不能再调用任何 `TestBed` 中的配置方法,既不能调 `configureTestingModule()`,也不能调用任何 `override...` 方法。如果你试图这么做,`TestBed` 就会抛出错误。
Make `compileComponents()` the last step Make `compileComponents()` the last step
before calling `TestBed.createComponent()`. before calling `TestBed.createComponent()`.
确保 `compileComponents()` 是调用 `TestBed.createComponent()` 之前的最后一步。
#### The synchronous _beforeEach_ #### The synchronous _beforeEach_
#### 同步的 `beforeEach`
The second, synchronous `beforeEach()` contains the remaining setup steps, The second, synchronous `beforeEach()` contains the remaining setup steps,
which include creating the component and querying for elements to inspect. which include creating the component and querying for elements to inspect.
第二个同步 `beforeEach()` 的例子包含剩下的设置步骤,
包括创建组件和查询那些要检查的元素。
<code-example <code-example
path="testing/src/app/banner/banner-external.component.spec.ts" path="testing/src/app/banner/banner-external.component.spec.ts"
region="sync-before-each" region="sync-before-each"
@ -3319,12 +3440,19 @@ You can count on the test runner to wait for the first asynchronous `beforeEach`
#### Consolidated setup #### Consolidated setup
#### 整理过的设置代码
You can consolidate the two `beforeEach()` functions into a single, async `beforeEach()`. You can consolidate the two `beforeEach()` functions into a single, async `beforeEach()`.
你可以把这两个 `beforeEach()` 函数重整成一个异步的 `beforeEach()`
The `compileComponents()` method returns a promise so you can perform the The `compileComponents()` method returns a promise so you can perform the
synchronous setup tasks _after_ compilation by moving the synchronous code synchronous setup tasks _after_ compilation by moving the synchronous code
into a `then(...)` callback. into a `then(...)` callback.
`compileComponents()` 方法返回一个承诺,所以你可以通过把同步代码移到 `then(...)` 回调中,
以便在编译完成*之后* 执行那些同步设置任务。
<code-example <code-example
path="testing/src/app/banner/banner-external.component.spec.ts" path="testing/src/app/banner/banner-external.component.spec.ts"
region="one-before-each" region="one-before-each"
@ -3334,19 +3462,29 @@ into a `then(...)` callback.
#### _compileComponents()_ is harmless #### _compileComponents()_ is harmless
#### `compileComponents()` 是无害的
There's no harm in calling `compileComponents()` when it's not required. There's no harm in calling `compileComponents()` when it's not required.
在不需要 `compileComponents()` 的时候调用它也不会有害处。
The component test file generated by the CLI calls `compileComponents()` The component test file generated by the CLI calls `compileComponents()`
even though it is never required when running `ng test`. even though it is never required when running `ng test`.
虽然在运行 `ng test` 时永远都不需要调用 `compileComponents()`,但 CLI 生成的组件测试文件还是会调用它。
The tests in this guide only call `compileComponents` when necessary. The tests in this guide only call `compileComponents` when necessary.
但这篇指南中的这些测试只会在必要时才调用 `compileComponents`
<hr> <hr>
{@a import-module} {@a import-module}
### Setup with module imports ### Setup with module imports
### 设置模块的 `imports`
Earlier component tests configured the testing module with a few `declarations` like this: Earlier component tests configured the testing module with a few `declarations` like this:
此前的组件测试程序使用了一些`declarations`来配置模块,就像这样: 此前的组件测试程序使用了一些`declarations`来配置模块,就像这样:
@ -3410,19 +3548,29 @@ One approach is to configure the testing module from the individual pieces as in
Notice that the `beforeEach()` is asynchronous and calls `TestBed.compileComponents` Notice that the `beforeEach()` is asynchronous and calls `TestBed.compileComponents`
because the `HeroDetailComponent` has an external template and css file. because the `HeroDetailComponent` has an external template and css file.
注意,`beforeEach()` 是异步的,它调用 `TestBed.compileComponents` 是因为 `HeroDetailComponent` 有外部模板和 CSS 文件。
As explained in [_Calling compileComponents()_](#compile-components) above, As explained in [_Calling compileComponents()_](#compile-components) above,
these tests could be run in a non-CLI environment these tests could be run in a non-CLI environment
where Angular would have to compile them in the browser. where Angular would have to compile them in the browser.
如前面的[调用 `compileComponents()`](#compile-components) 中所解释的那样,这些测试可以运行在非 CLI 环境下,那里 Angular 并不会在浏览器中编译它们。
</div> </div>
#### Import a shared module #### Import a shared module
#### 导入共享模块
Because many app components need the `FormsModule` and the `TitleCasePipe`, the developer created Because many app components need the `FormsModule` and the `TitleCasePipe`, the developer created
a `SharedModule` to combine these and other frequently requested parts. a `SharedModule` to combine these and other frequently requested parts.
因为很多应用组件都需要 `FormsModule``TitleCasePipe`,所以开发者创建了 `SharedModule` 来把它们及其它常用的部分组合在一起。
The test configuration can use the `SharedModule` too as seen in this alternative setup: The test configuration can use the `SharedModule` too as seen in this alternative setup:
这些测试配置也可以使用 `SharedModule`,如下所示:
<code-example <code-example
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="setup-shared-module" region="setup-shared-module"
@ -3438,10 +3586,15 @@ It's a bit tighter and smaller, with fewer import statements (not shown).
#### Import a feature module #### Import a feature module
#### 导入特性模块
The `HeroDetailComponent` is part of the `HeroModule` [Feature Module](guide/feature-modules) that aggregates more of the interdependent pieces The `HeroDetailComponent` is part of the `HeroModule` [Feature Module](guide/feature-modules) that aggregates more of the interdependent pieces
including the `SharedModule`. including the `SharedModule`.
Try a test configuration that imports the `HeroModule` like this one: Try a test configuration that imports the `HeroModule` like this one:
`HeroDetailComponent``HeroModule` 这个[特性模块](guide/feature-modules)的一部分,它聚合了更多相互依赖的片段,包括 `SharedModule`
试试下面这个导入了 `HeroModule` 的测试配置:
<code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="setup-hero-module" title="app/hero/hero-detail.component.spec.ts (HeroModule setup)" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="setup-hero-module" title="app/hero/hero-detail.component.spec.ts (HeroModule setup)" linenums="false"></code-example>
That's _really_ crisp. Only the _test doubles_ in the `providers` remain. Even the `HeroDetailComponent` declaration is gone. That's _really_ crisp. Only the _test doubles_ in the `providers` remain. Even the `HeroDetailComponent` declaration is gone.
@ -3452,12 +3605,16 @@ In fact, if you try to declare it, Angular will throw an error because
`HeroDetailComponent` is declared in both the `HeroModule` and the `DynamicTestModule` `HeroDetailComponent` is declared in both the `HeroModule` and the `DynamicTestModule`
created by the `TestBed`. created by the `TestBed`.
事实上如果你试图声明它Angular 就会抛出一个错误,因为 `HeroDetailComponent` 同时声明在了 `HeroModule``TestBed` 创建的 `DynamicTestModule` 中。
<div class="alert is-helpful"> <div class="alert is-helpful">
Importing the component's feature module can be the easiest way to configure tests Importing the component's feature module can be the easiest way to configure tests
when there are many mutual dependencies within the module and when there are many mutual dependencies within the module and
the module is small, as feature modules tend to be. the module is small, as feature modules tend to be.
如果模块中有很多共同依赖,并且该模块很小(这也是特性模块的应有形态),那么直接导入组件的特性模块可以成为配置这些测试的简易方式。
</div> </div>
<hr> <hr>
@ -3466,6 +3623,8 @@ the module is small, as feature modules tend to be.
### Override component providers ### Override component providers
### 改写组件的服务提供商
The `HeroDetailComponent` provides its own `HeroDetailService`. The `HeroDetailComponent` provides its own `HeroDetailService`.
`HeroDetailComponent`提供自己的`HeroDetailService`服务。 `HeroDetailComponent`提供自己的`HeroDetailService`服务。
@ -3481,9 +3640,14 @@ Those are providers for the _testing module_, not the component. They prepare th
Angular creates the component with its _own_ injector, which is a _child_ of the fixture injector. Angular creates the component with its _own_ injector, which is a _child_ of the fixture injector.
It registers the component's providers (the `HeroDetailService` in this case) with the child injector. It registers the component's providers (the `HeroDetailService` in this case) with the child injector.
Angular 会使用自己的注入器来创建这些组件,这个注入器是夹具的注入器的子注入器。
它使用这个子注入器注册了该组件服务提供商(这里是 `HeroDetailService` )。
A test cannot get to child injector services from the fixture injector. A test cannot get to child injector services from the fixture injector.
And `TestBed.configureTestingModule` can't configure them either. And `TestBed.configureTestingModule` can't configure them either.
测试没办法从测试夹具的注入器中获取子注入器中的服务,而 `TestBed.configureTestingModule` 也没法配置它们。
Angular has been creating new instances of the real `HeroDetailService` all along! Angular has been creating new instances of the real `HeroDetailService` all along!
Angular始终都在创建真实`HeroDetailService`的实例。 Angular始终都在创建真实`HeroDetailService`的实例。
@ -3505,6 +3669,8 @@ Fortunately, the `HeroDetailService` delegates responsibility for remote data ac
The [previous test configuration](#feature-module-import) replaces the real `HeroService` with a `TestHeroService` The [previous test configuration](#feature-module-import) replaces the real `HeroService` with a `TestHeroService`
that intercepts server requests and fakes their responses. that intercepts server requests and fakes their responses.
[前面的测试配置](#feature-module-import)使用 `TestHeroService` 替换了真实的 `HeroService`,它拦截了发往服务器的请求,并伪造了服务器的响应。
</div> </div>
What if you aren't so lucky. What if faking the `HeroService` is hard? What if you aren't so lucky. What if faking the `HeroService` is hard?
@ -3521,10 +3687,14 @@ as seen in the following setup variation:
Notice that `TestBed.configureTestingModule` no longer provides a (fake) `HeroService` because it's [not needed](#spy-stub). Notice that `TestBed.configureTestingModule` no longer provides a (fake) `HeroService` because it's [not needed](#spy-stub).
注意,`TestBed.configureTestingModule` 不再提供(伪造的)`HeroService`,因为[并不需要](#spy-stub)。
{@a override-component-method} {@a override-component-method}
#### The _overrideComponent_ method #### The _overrideComponent_ method
#### `overrideComponent` 方法
Focus on the `overrideComponent` method. Focus on the `overrideComponent` method.
注意这个`overrideComponent`方法。 注意这个`overrideComponent`方法。
@ -3534,6 +3704,8 @@ Focus on the `overrideComponent` method.
It takes two arguments: the component type to override (`HeroDetailComponent`) and an override metadata object. It takes two arguments: the component type to override (`HeroDetailComponent`) and an override metadata object.
The [overide metadata object](#metadata-override-object) is a generic defined as follows: The [overide metadata object](#metadata-override-object) is a generic defined as follows:
它接受两个参数:要改写的组件类(`HeroDetailComponent`),以及用于改写的元数据对象:
<code-example format="." language="javascript"> <code-example format="." language="javascript">
type MetadataOverride<T> = { type MetadataOverride<T> = {
@ -3568,6 +3740,8 @@ The type parameter, `T`, is the kind of metadata you'd pass to the `@Component`
#### Provide a _spy stub_ (_HeroDetailServiceSpy_) #### Provide a _spy stub_ (_HeroDetailServiceSpy_)
#### 提供`间谍桩` (`HeroDetailServiceSpy`)
This example completely replaces the component's `providers` array with a new array containing a `HeroDetailServiceSpy`. This example completely replaces the component's `providers` array with a new array containing a `HeroDetailServiceSpy`.
这个例子把组件的`providers`数组完全替换成了一个包含`HeroDetailServiceSpy`的新数组。 这个例子把组件的`providers`数组完全替换成了一个包含`HeroDetailServiceSpy`的新数组。
@ -3593,6 +3767,8 @@ Accordingly, the stub implements its methods as spies:
#### The override tests #### The override tests
#### 改写测试
Now the tests can control the component's hero directly by manipulating the spy-stub's `testHero` Now the tests can control the component's hero directly by manipulating the spy-stub's `testHero`
and confirm that service methods were called. and confirm that service methods were called.
@ -3604,6 +3780,8 @@ and confirm that service methods were called.
#### More overrides #### More overrides
#### 更多的改写
The `TestBed.overrideComponent` method can be called multiple times for the same or different components. The `TestBed.overrideComponent` method can be called multiple times for the same or different components.
The `TestBed` offers similar `overrideDirective`, `overrideModule`, and `overridePipe` methods The `TestBed` offers similar `overrideDirective`, `overrideModule`, and `overridePipe` methods
for digging into and replacing parts of these other classes. for digging into and replacing parts of these other classes.
@ -3621,6 +3799,8 @@ Explore the options and combinations on your own.
## Attribute Directive Testing ## Attribute Directive Testing
## 属性型指令的测试
An _attribute directive_ modifies the behavior of an element, component or another directive. An _attribute directive_ modifies the behavior of an element, component or another directive.
Its name reflects the way the directive is applied: as an attribute on a host element. Its name reflects the way the directive is applied: as an attribute on a host element.
@ -3645,6 +3825,8 @@ It's used throughout the application, perhaps most simply in the `AboutComponent
Testing the specific use of the `HighlightDirective` within the `AboutComponent` requires only the Testing the specific use of the `HighlightDirective` within the `AboutComponent` requires only the
techniques explored above (in particular the ["Shallow test"](#nested-component-tests) approach). techniques explored above (in particular the ["Shallow test"](#nested-component-tests) approach).
要想在 `AboutComponent` 中测试 `HighlightDirective` 的具体用法,只要使用在[“浅层测试”](#nested-component-tests)部分用过的技术即可。
<code-example path="testing/src/app/about/about.component.spec.ts" region="tests" title="app/about/about.component.spec.ts" linenums="false"></code-example> <code-example path="testing/src/app/about/about.component.spec.ts" region="tests" title="app/about/about.component.spec.ts" linenums="false"></code-example>
However, testing a single use case is unlikely to explore the full range of a directive's capabilities. However, testing a single use case is unlikely to explore the full range of a directive's capabilities.
@ -3658,9 +3840,13 @@ but attribute directives like this one tend to manipulate the DOM.
Isolated unit tests don't touch the DOM and, therefore, Isolated unit tests don't touch the DOM and, therefore,
do not inspire confidence in the directive's efficacy. do not inspire confidence in the directive's efficacy.
*只针对类的测试*可能很有用,
但是像这个一样的属性型指令肯定要操纵 DOM。
隔离出的单元测试不能接触 DOM因此也就没办法证明该指令的有效性。
A better solution is to create an artificial test component that demonstrates all ways to apply the directive. A better solution is to create an artificial test component that demonstrates all ways to apply the directive.
更好的方法是创建一个展示所有使用该组件的方法的人工测试组件。 更好的方法是创建一个能展示该指令所有用法的人造测试组件。
<code-example path="testing/src/app/shared/highlight.directive.spec.ts" region="test-component" title="app/shared/highlight.directive.spec.ts (TestComponent)" linenums="false"></code-example> <code-example path="testing/src/app/shared/highlight.directive.spec.ts" region="test-component" title="app/shared/highlight.directive.spec.ts (TestComponent)" linenums="false"></code-example>
@ -3718,6 +3904,8 @@ and its `defaultColor`.
## Pipe Testing ## Pipe Testing
## 管道测试
Pipes are easy to test without the Angular testing utilities. Pipes are easy to test without the Angular testing utilities.
管道很容易测试无需Angular测试工具。 管道很容易测试无需Angular测试工具。
@ -3752,6 +3940,8 @@ Use simple Jasmine to explore the expected cases and the edge cases.
#### Write DOM tests too #### Write DOM tests too
#### 也能编写 DOM 测试
These are tests of the pipe _in isolation_. These are tests of the pipe _in isolation_.
They can't tell if the `TitleCasePipe` is working properly as applied in the application components. They can't tell if the `TitleCasePipe` is working properly as applied in the application components.
@ -3770,6 +3960,8 @@ Consider adding component tests such as this one:
## Test debugging ## Test debugging
## 测试程序的调试
Debug specs in the browser in the same way that you debug an application. Debug specs in the browser in the same way that you debug an application.
在浏览器中像调试应用一样调试测试程序spec。 在浏览器中像调试应用一样调试测试程序spec。
@ -3812,6 +4004,8 @@ Debug specs in the browser in the same way that you debug an application.
## Testing Utility APIs ## Testing Utility APIs
## 测试工具 API
This section takes inventory of the most useful Angular testing features and summarizes what they do. This section takes inventory of the most useful Angular testing features and summarizes what they do.
本节将最有用的Angular测试功能提取出来并总结了它们的作用。 本节将最有用的Angular测试功能提取出来并总结了它们的作用。
@ -3819,6 +4013,9 @@ This section takes inventory of the most useful Angular testing features and sum
The Angular testing utilities include the `TestBed`, the `ComponentFixture`, and a handful of functions that control the test environment. The Angular testing utilities include the `TestBed`, the `ComponentFixture`, and a handful of functions that control the test environment.
The [_TestBed_](#testbed-api-summary) and [_ComponentFixture_](#component-fixture-api-summary) classes are covered separately. The [_TestBed_](#testbed-api-summary) and [_ComponentFixture_](#component-fixture-api-summary) classes are covered separately.
Angular 的测试工具集包括 `TestBed``ComponentFixture` 和一些用来控制测试环境的便捷函数。
[`TestBed`](#testbed-api-summary) 和 [`ComponentFixture`](#component-fixture-api-summary) 部分单独讲过它们。
Here's a summary of the stand-alone functions, in order of likely utility: Here's a summary of the stand-alone functions, in order of likely utility:
下面是一些独立函数的总结,以使用频率排序: 下面是一些独立函数的总结,以使用频率排序:
@ -3858,6 +4055,9 @@ Here's a summary of the stand-alone functions, in order of likely utility:
Runs the body of a test (`it`) or setup (`beforeEach`) function within a special _async test zone_. Runs the body of a test (`it`) or setup (`beforeEach`) function within a special _async test zone_.
See [discussion above](#async). See [discussion above](#async).
在一个特殊的* async 测试区域*中运行测试(`it`)的函数体或设置函数(`beforeEach`)。
参见[前面的讨论](#async)。
</td> </td>
</tr> </tr>
@ -3875,6 +4075,9 @@ Here's a summary of the stand-alone functions, in order of likely utility:
Runs the body of a test (`it`) within a special _fakeAsync test zone_, enabling Runs the body of a test (`it`) within a special _fakeAsync test zone_, enabling
a linear control flow coding style. See [discussion above](#fake-async). a linear control flow coding style. See [discussion above](#fake-async).
在一个特殊的* fakeAsync 测试区域*中运行测试(`it`)的函数体,以便启用线性风格的控制流。
参见[前面的讨论](#fake-async)。
</td> </td>
</tr> </tr>
@ -3892,6 +4095,8 @@ Here's a summary of the stand-alone functions, in order of likely utility:
Simulates the passage of time and the completion of pending asynchronous activities Simulates the passage of time and the completion of pending asynchronous activities
by flushing both _timer_ and _micro-task_ queues within the _fakeAsync test zone_. by flushing both _timer_ and _micro-task_ queues within the _fakeAsync test zone_.
通过在* fakeAsync 测试区域*中刷新定时器和微任务micro-task队列来仿真时间的流逝以及异步活动的完成。
<div class="l-sub-section"> <div class="l-sub-section">
The curious, dedicated reader might enjoy this lengthy blog post, The curious, dedicated reader might enjoy this lengthy blog post,
@ -3908,6 +4113,10 @@ Here's a summary of the stand-alone functions, in order of likely utility:
clearing asynchronous activities scheduled within that timeframe. clearing asynchronous activities scheduled within that timeframe.
See [discussion above](#tick). See [discussion above](#tick).
接受一个可选参数,它可以把虚拟时钟往前推进特定的微秒数。
清除调度到那个时间帧中的异步活动。
参见[前面的讨论](#tick)。
</td> </td>
</tr> </tr>
@ -3926,6 +4135,10 @@ Here's a summary of the stand-alone functions, in order of likely utility:
It cannot inject a service provided by the component itself. It cannot inject a service provided by the component itself.
See discussion of the [debugElement.injector](#get-injected-services). See discussion of the [debugElement.injector](#get-injected-services).
从当前的 `TestBed` 注入器中把一个或多个服务注入到一个测试函数中。
它不能用于注入组件自身提供的服务。
参见 [`debugElement.injector`](#get-injected-services) 部分的讨论。
</td> </td>
</tr> </tr>
@ -3995,6 +4208,8 @@ Here's a summary of the stand-alone functions, in order of likely utility:
A provider token for a service that turns on [automatic change detection](#automatic-change-detection). A provider token for a service that turns on [automatic change detection](#automatic-change-detection).
一个服务提供商令牌,用于开启[自动变更检测](#automatic-change-detection)。
</td> </td>
</tr> </tr>
@ -4030,6 +4245,8 @@ Here's a summary of the stand-alone functions, in order of likely utility:
#### _TestBed_ class summary #### _TestBed_ class summary
#### `TestBed` 类小结
The `TestBed` class is one of the principal Angular testing utilities. The `TestBed` class is one of the principal Angular testing utilities.
Its API is quite large and can be overwhelming until you've explored it, Its API is quite large and can be overwhelming until you've explored it,
a little at a time. Read the early part of this guide first a little at a time. Read the early part of this guide first
@ -4156,6 +4373,10 @@ Here are the most important static methods, in order of likely utility.
or `styleUrls` because fetching component template and style files is necessarily asynchronous. or `styleUrls` because fetching component template and style files is necessarily asynchronous.
See [above](#compile-components). See [above](#compile-components).
在配置好测试模块之后,异步编译它。
如果测试模块中的*任何一个*组件具有 `templateUrl``styleUrls`,那么你**必须**调用这个方法,因为获取组件的模板或样式文件必须是异步的。
参见[前面的讨论](#compile-components)。
After calling `compileComponents`, the `TestBed` configuration is frozen for the duration of the current spec. After calling `compileComponents`, the `TestBed` configuration is frozen for the duration of the current spec.
调用完`compileComponents`之后,`TestBed`的配置就会在当前测试期间被冻结。 调用完`compileComponents`之后,`TestBed`的配置就会在当前测试期间被冻结。
@ -4281,12 +4502,18 @@ Here are the most important static methods, in order of likely utility.
The `inject` function is often adequate for this purpose. The `inject` function is often adequate for this purpose.
But `inject` throws an error if it can't provide the service. But `inject` throws an error if it can't provide the service.
`inject` 函数通常都能胜任这项工作,但是如果它没法提供该服务时就会抛出一个异常。
What if the service is optional? What if the service is optional?
如果该服务是可选的呢?
The `TestBed.get()` method takes an optional second parameter, The `TestBed.get()` method takes an optional second parameter,
the object to return if Angular can't find the provider the object to return if Angular can't find the provider
(`null` in this example): (`null` in this example):
`TestBed.get()` 方法可以接受可选的第二参数,当 Angular 找不到指定的服务提供商时,就会返回该对象(下面这个例子中是 `null`
<code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="testbed-get-w-null" title="app/demo/demo.testbed.spec.ts" linenums="false"></code-example> <code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="testbed-get-w-null" title="app/demo/demo.testbed.spec.ts" linenums="false"></code-example>
After calling `get`, the `TestBed` configuration is frozen for the duration of the current spec. After calling `get`, the `TestBed` configuration is frozen for the duration of the current spec.
@ -4363,11 +4590,13 @@ These are rarely needed.
#### The _ComponentFixture_ #### The _ComponentFixture_
#### `ComponentFixture`
The `TestBed.createComponent<T>` The `TestBed.createComponent<T>`
creates an instance of the component `T` creates an instance of the component `T`
and returns a strongly typed `ComponentFixture` for that component. and returns a strongly typed `ComponentFixture` for that component.
`TestBed.createComponent<T>`创建一个组件`T`的实例,并为该组件返回一个强类型的`ComponentFixture` `TestBed.createComponent<T>`创建一个组件`T`的实例,并为该组件返回一个强类型的 `ComponentFixture`
The `ComponentFixture` properties and methods provide access to the component, The `ComponentFixture` properties and methods provide access to the component,
its DOM representation, and aspects of its Angular environment. its DOM representation, and aspects of its Angular environment.
@ -4378,6 +4607,8 @@ its DOM representation, and aspects of its Angular environment.
#### _ComponentFixture_ properties #### _ComponentFixture_ properties
#### `ComponentFixture` 的属性
Here are the most important properties for testers, in order of likely utility. Here are the most important properties for testers, in order of likely utility.
下面是对测试最重要的属性,以使用频率排序: 下面是对测试最重要的属性,以使用频率排序:
@ -4439,6 +4670,9 @@ Here are the most important properties for testers, in order of likely utility.
The `debugElement` provides insight into the component and its DOM element during test and debugging. The `debugElement` provides insight into the component and its DOM element during test and debugging.
It's a critical property for testers. The most interesting members are covered [below](#debug-element-details). It's a critical property for testers. The most interesting members are covered [below](#debug-element-details).
`debugElement` 提供了在测试和调试期间深入探查组件及其 DOM 元素的功能。
它对于测试者是一个极其重要的属性。它的大多数主要成员在[后面](#debug-element-details)都有讲解。
</td> </td>
</tr> </tr>
@ -4491,6 +4725,8 @@ Here are the most important properties for testers, in order of likely utility.
#### _ComponentFixture_ methods #### _ComponentFixture_ methods
#### `ComponentFixture` 的方法
The _fixture_ methods cause Angular to perform certain tasks on the component tree. The _fixture_ methods cause Angular to perform certain tasks on the component tree.
Call these method to trigger Angular behavior in response to simulated user action. Call these method to trigger Angular behavior in response to simulated user action.
@ -4643,6 +4879,9 @@ Here are the most useful methods for testers.
asynchronous change detection, hook that promise. asynchronous change detection, hook that promise.
See [above](#when-stable). See [above](#when-stable).
要想在完成了异步活动或异步变更检测之后再继续测试,可以对那个承诺对象进行挂钩。
参见 [前面](#when-stable)。
</td> </td>
</tr> </tr>
@ -4737,6 +4976,8 @@ Here are the most useful `DebugElement` members for testers, in approximate orde
Calling `query(predicate: Predicate<DebugElement>)` returns the first `DebugElement` Calling `query(predicate: Predicate<DebugElement>)` returns the first `DebugElement`
that matches the [predicate](#query-predicate) at any depth in the subtree. that matches the [predicate](#query-predicate) at any depth in the subtree.
调用 `query(predicate: Predicate<DebugElement>)` 会在子树的任意深度中查找能和[谓词函数](#query-predicate)匹配的第一个 `DebugElement`
</td> </td>
</tr> </tr>
@ -4754,6 +4995,8 @@ Here are the most useful `DebugElement` members for testers, in approximate orde
Calling `queryAll(predicate: Predicate<DebugElement>)` returns all `DebugElements` Calling `queryAll(predicate: Predicate<DebugElement>)` returns all `DebugElements`
that matches the [predicate](#query-predicate) at any depth in subtree. that matches the [predicate](#query-predicate) at any depth in subtree.
调用 `queryAll(predicate: Predicate<DebugElement>)` 会在子树的任意深度中查找能和[谓词函数](#query-predicate)匹配的所有 `DebugElement`
</td> </td>
</tr> </tr>
@ -4835,6 +5078,8 @@ Here are the most useful `DebugElement` members for testers, in approximate orde
The immediate `DebugElement` children. Walk the tree by descending through `children`. The immediate `DebugElement` children. Walk the tree by descending through `children`.
`DebugElement` 的直接子元素。可以通过继续深入 `children` 来遍历这棵树。
<div class="l-sub-section"> <div class="l-sub-section">
`DebugElement` also has `childNodes`, a list of `DebugNode` objects. `DebugElement` also has `childNodes`, a list of `DebugNode` objects.
@ -4901,6 +5146,8 @@ Here are the most useful `DebugElement` members for testers, in approximate orde
The second parameter is the _event object_ expected by the handler. The second parameter is the _event object_ expected by the handler.
See [above](#trigger-event-handler). See [above](#trigger-event-handler).
如果在该元素的 `listeners` 集合中有相应的监听器,就根据名字触发这个事件。
If the event lacks a listener or there's some other problem, If the event lacks a listener or there's some other problem,
consider calling `nativeElement.dispatchEvent(eventObject)`. consider calling `nativeElement.dispatchEvent(eventObject)`.
@ -5027,10 +5274,14 @@ Angular的`By`类为常用条件方法提供了三个静态方法:
## Frequently Asked Questions ## Frequently Asked Questions
## 常见问题
{@a q-spec-file-location} {@a q-spec-file-location}
#### Why put spec file next to the file it tests? #### Why put spec file next to the file it tests?
#### 为什么要把测试文件和被测文件放在一起?
It's a good idea to put unit test spec files in the same folder It's a good idea to put unit test spec files in the same folder
as the application source code files that they test: as the application source code files that they test:
@ -5062,6 +5313,8 @@ as the application source code files that they test:
#### When would I put specs in a test folder? #### When would I put specs in a test folder?
#### 什么时候我该把测试文件放进单独的 `test` 文件夹中?
Application integration specs can test the interactions of multiple parts Application integration specs can test the interactions of multiple parts
spread across folders and modules. spread across folders and modules.
They don't really belong to any part in particular, so they don't have a They don't really belong to any part in particular, so they don't have a
@ -5083,25 +5336,45 @@ next to their corresponding helper files.
#### Why not rely on E2E tests of DOM integration? #### Why not rely on E2E tests of DOM integration?
#### 为什么不依赖 E2E 测试来保障 DOM 集成后的正确性?
The component DOM tests describe in this guide often require extensive setup and The component DOM tests describe in this guide often require extensive setup and
advanced techniques where as the [class-only test](#component-class-testing) advanced techniques where as the [class-only test](#component-class-testing)
were comparatively simple. were comparatively simple.
本指南中讲的组件 DOM 测试通常需要大量的准备工作以及高级技巧,不像[只用类的测试](#component-class-testing)那样简单。
Why not defer DOM integration tests to end-to-end (E2E) testing? Why not defer DOM integration tests to end-to-end (E2E) testing?
为什么不等到端到端E2E测试阶段再对 DOM 进行集成测试呢?
E2E tests are great for high-level validation of the entire system. E2E tests are great for high-level validation of the entire system.
But they can't give you the comprehensive test coverage that you'd expect from unit tests. But they can't give you the comprehensive test coverage that you'd expect from unit tests.
E2E 测试对于整个系统的高层验证非常好用。
但是它们没法给你像单元测试这样全面的测试覆盖率。
E2E tests are difficult to write and perform poorly compared to unit tests. E2E tests are difficult to write and perform poorly compared to unit tests.
They break easily, often due to changes or misbehavior far removed from the site of breakage. They break easily, often due to changes or misbehavior far removed from the site of breakage.
E2E 测试很难写,并且执行性能也赶不上单元测试。
它们很容易被破坏,而且经常是因为某些远离故障点的修改或不当行为而导致的。
E2E tests can't easily reveal how your components behave when things go wrong, E2E tests can't easily reveal how your components behave when things go wrong,
such as missing or bad data, lost connectivity, and remote service failures. such as missing or bad data, lost connectivity, and remote service failures.
当出错时E2E 测试不能轻松揭露你的组件出了什么问题,
比如丢失或错误的数据、网络失去连接或远端服务器挂了。
E2E tests for apps that update a database, E2E tests for apps that update a database,
send an invoice, or charge a credit card require special tricks and back-doors to prevent send an invoice, or charge a credit card require special tricks and back-doors to prevent
accidental corruption of remote resources. accidental corruption of remote resources.
It can even be hard to navigate to the component you want to test. It can even be hard to navigate to the component you want to test.
如果 E2E 的测试对象要更新数据库、发送发票或收取信用卡,就需要一些特殊的技巧和后门来防止远程资源被意外破坏。
它甚至可能都难以导航到你要测试的组件。
Because of these many obstacles, you should test DOM interaction Because of these many obstacles, you should test DOM interaction
with unit testing techniques as much as possible. with unit testing techniques as much as possible.
由于存在这么多障碍,你应该尽可能使用单元测试技术来测试 DOM 交互。