fix: 翻译完了《测试》的剩余部分
This commit is contained in:
parent
6d5cfd568b
commit
cae70fab87
@ -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 交互。
|
||||||
|
Loading…
x
Reference in New Issue
Block a user