translate: testing to line 2150

This commit is contained in:
rexebin 2016-09-24 22:28:06 +01:00
parent b848c86570
commit d3b1c3628e
1 changed files with 121 additions and 23 deletions

View File

@ -146,7 +146,7 @@ block includes
1. [Test a routed component](#routed-component) 1. [Test a routed component](#routed-component)
1. [测试路由组件](#routed-component) 1. [测试路由器的组件](#routed-component)
- [_inject_](#inject) - [_inject_](#inject)
@ -154,7 +154,7 @@ block includes
1. [Test a routed component with parameters](#routed-component-w-param) 1. [Test a routed component with parameters](#routed-component-w-param)
1. [测试一个带有参数的被路由的组件](#routed-component-w-param) 1. [测试一个带有路由和路由参数的组件](#routed-component-w-param)
- [_Observable_ test double](#stub-observable) - [_Observable_ test double](#stub-observable)
@ -346,7 +346,7 @@ table(width="100%")
[karma测试运行器](https://karma-runner.github.io/1.0/index.html)是在开发应用的过程中 [karma测试运行器](https://karma-runner.github.io/1.0/index.html)是在开发应用的过程中
编写和运行单元测试的理想工具。 编写和运行单元测试的理想工具。
它能成为项目开发和连续一体化进程的一个不可分割的一部分。本章讲述了如何用Karma设置和运行测试。 它能成为项目开发和连续一体化进程的不可分割的一部分。本章讲述了如何用Karma设置和运行测试。
tr(style=top) tr(style=top)
td(style="vertical-align: top") Protractor td(style="vertical-align: top") Protractor
@ -359,7 +359,7 @@ table(width="100%")
and assert that the application responds in the browser as expected. and assert that the application responds in the browser as expected.
使用`Protractor`来编写和运行_端对端(e2e)_测试。端对端测试**像用户体验应用程序那样**探索它。 使用`Protractor`来编写和运行_端对端(e2e)_测试。端对端测试**像用户体验应用程序那样**探索它。
在端对端测试中,一个进程运行真正的应用,另一个进程运行Protractor测试模拟用户行为判断应用在浏览器中的反应是否正确。 在端对端测试中,一条进程运行真正的应用,另一条进程运行Protractor测试模拟用户行为判断应用在浏览器中的反应是否正确。
.l-hr .l-hr
#setup #setup
@ -639,7 +639,7 @@ code-example(format="." language="bash").
- Click the "DEBUG" button; it opens a new browser tab and re-runs the tests - Click the "DEBUG" button; it opens a new browser tab and re-runs the tests
- 点击“DEBUG”按钮它打开一个新的浏览器标签页并重新开始运行测试 - 点击“DEBUG”按钮它打开一页新浏览器标签并重新开始运行测试
- Open the browser's “Developer Tools” (F12 or Ctrl-Shift-I). - Open the browser's “Developer Tools” (F12 or Ctrl-Shift-I).
@ -736,7 +736,7 @@ a(href="#top").to-top 回到顶部
that almost everyone needs. that almost everyone needs.
在每个spec之前`TestBed`将自己重设为初始状态。 在每个spec之前`TestBed`将自己重设为初始状态。
这个初始状态包含了一默认的、几乎所有情况都需要的测试模块配置,包括可声明类(组件、指令和管道)和提供商(其中一些是伪造的)。 这个初始状态包含了一默认的、几乎所有情况都需要的测试模块配置,包括可声明类(组件、指令和管道)和提供商(其中一些是伪造的)。
.l-sub-section .l-sub-section
:marked :marked
@ -913,13 +913,13 @@ a(href="#top").to-top 回到顶部
:marked :marked
The `queryAll` method returns an array of _all_ `DebugElements` that satisfy the predicate. The `queryAll` method returns an array of _all_ `DebugElements` that satisfy the predicate.
`queryAll`方法返回一数组,包含所有`DebugElement`中满足predicate的元素。 `queryAll`方法返回一数组,包含所有`DebugElement`中满足predicate的元素。
A _predicate_ is a function that returns a boolean. A _predicate_ is a function that returns a boolean.
A query predicate receives a `DebugElement` and returns `true` if the element meets the selection criteria. A query predicate receives a `DebugElement` and returns `true` if the element meets the selection criteria.
一个**predicate**是一个返回布尔值的函数。 **predicate**是一个返回布尔值的函数。
一个查询predicate接受一个`DebugElement`,如果元素符合选择条件便返回`true`。 predicate查询接受`DebugElement`,如果元素符合选择条件便返回`true`。
:marked :marked
The **`By`** class is an Angular testing utility that produces useful predicates. The **`By`** class is an Angular testing utility that produces useful predicates.
@ -927,7 +927,7 @@ a(href="#top").to-top 回到顶部
<a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_started/Selectors" target="_blank">standard CSS selector</a> <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_started/Selectors" target="_blank">standard CSS selector</a>
predicate that filters the same way as a jQuery selector. predicate that filters the same way as a jQuery selector.
**`By`**类是一个Angular测试工具它生成有用的predicate。 **`By`**类是Angular测试工具之一它生成有用的predicate。
它的`By.css`静态方法产生一个<a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_started/Selectors" target="_blank">标准CSS选择器</a> 它的`By.css`静态方法产生一个<a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_started/Selectors" target="_blank">标准CSS选择器</a>
predicate与JQuery选择器相同的方式过滤。 predicate与JQuery选择器相同的方式过滤。
@ -985,7 +985,7 @@ a(href="#top").to-top 回到顶部
It gives the tester an opportunity to inspect or change the state of It gives the tester an opportunity to inspect or change the state of
the component _before Angular initiates data binding or calls lifecycle hooks_. the component _before Angular initiates data binding or calls lifecycle hooks_.
此行为(或者缺乏的行为)是有意的。**在Angular初始化数据绑定或者调用生命周期钩子**之前,它给测试者一个机会查看或者改变组件的状态。 此行为(或者缺乏的行为)是有意的。**在Angular初始化数据绑定或者调用生命周期钩子**之前,它给测试者一个机会查看或者改变组件的状态。
#auto-detect-changes #auto-detect-changes
:marked :marked
@ -1018,7 +1018,7 @@ a(href="#top").to-top 回到顶部
第二和第三个测试显示了一个重要的局限性。 第二和第三个测试显示了一个重要的局限性。
Angular测试环境**不会**知道测试改变了组件的`title`属性。 Angular测试环境**不会**知道测试改变了组件的`title`属性。
**自动检测**只对**异步行为**比如承诺的解析计时器和DOM时间作出反应。 **自动检测**只对**异步行为**比如承诺的解析计时器和DOM时间作出反应。
但是一个直接的,同步的组件属性值的变化时不会触发**自动检测**的。 但是直接的组件属性值的同步更新是不会触发**自动检测**的。
测试必须手动调用`fixture.detectChange()`,来触发新一轮的变化检测周期。 测试必须手动调用`fixture.detectChange()`,来触发新一轮的变化检测周期。
.alert.is-helpful .alert.is-helpful
@ -1088,7 +1088,7 @@ a(href="#top").to-top 回到顶部
This particular test suite supplies a minimal `UserService` stub that satisfies the needs of the `WelcomeComponent` This particular test suite supplies a minimal `UserService` stub that satisfies the needs of the `WelcomeComponent`
and its tests: and its tests:
这个测试套件提供了一个最小化的`UserService` stub,用来满足`WelcomeComponent`和它的测试的需求: 这个测试套件提供了一个最小化的`UserService`,用来满足`WelcomeComponent`和它的测试的需求:
+makeExample('testing/ts/app/welcome.component.spec.ts', 'user-service-stub')(format='.') +makeExample('testing/ts/app/welcome.component.spec.ts', 'user-service-stub')(format='.')
@ -1106,7 +1106,7 @@ a(href="#top").to-top 回到顶部
There can be injectors at multiple levels, from the root injector created by the `TestBed` There can be injectors at multiple levels, from the root injector created by the `TestBed`
down through the component tree. down through the component tree.
Angular有一个层次化的注入系统。 Angular有一个层次化的注入系统。
可以有很多层注入器,从根`TestBed`创建的注入器下来贯穿整个组件数。 可以有很多层注入器,从根`TestBed`创建的注入器下来贯穿整个组件数。
The safest way to get the injected service, the way that **_always works_**, The safest way to get the injected service, the way that **_always works_**,
@ -1264,14 +1264,14 @@ a(href="#top").to-top 回到顶部
The spy is designed such that any call to `getQuote` receives an immediately resolved promise with a test quote. The spy is designed such that any call to `getQuote` receives an immediately resolved promise with a test quote.
The spy bypasses the actual `getQuote` method and therefore will not contact the server. The spy bypasses the actual `getQuote` method and therefore will not contact the server.
这个Spy的设计是所有调用`getQuote`的方法都会收到立刻解析的承诺,得到一预设的名言。Spy拦截了实际`getQuote`方法,所有它不会联系服务。 这个Spy的设计是所有调用`getQuote`的方法都会收到立刻解析的承诺,得到一预设的名言。Spy拦截了实际`getQuote`方法,所有它不会联系服务。
.l-sub-section .l-sub-section
:marked :marked
Faking a service instance and spying on the real service are _both_ great options. Faking a service instance and spying on the real service are _both_ great options.
Pick the one that seems easiest for the current test suite. Don't be afraid to change your mind. Pick the one that seems easiest for the current test suite. Don't be afraid to change your mind.
伪造一个服务实例和刺探真实服务都是好方法。挑选一对当前测试套件最简单的方法。你可以随时改变主意。 伪造一个服务实例和刺探真实服务都是好方法。挑选一对当前测试套件最简单的方法。你可以随时改变主意。
:marked :marked
Here are the tests with commentary to follow: Here are the tests with commentary to follow:
@ -1342,7 +1342,7 @@ a(href="#top").to-top 回到顶部
Consider also the [_fakeAsync_](#fake-async) alternative which affords a more linear coding experience. Consider also the [_fakeAsync_](#fake-async) alternative which affords a more linear coding experience.
在一个测试(比如`fixture.whenStable`)里面调用函数时,会继续体现它们的异步行为。 在一个测试(比如`fixture.whenStable`)里面调用函数时,会继续体现它们的异步行为。
考虑使用[_fakeAsync_](#fake-async),以获得一个更加直观的代码经验。 考虑使用[_fakeAsync_](#fake-async),以获得更加直观的代码经验。
#when-stable #when-stable
:marked :marked
@ -1402,7 +1402,7 @@ a(href="#top").to-top 回到顶部
The `fakeAsync` function is another of the Angular testing utilities. The `fakeAsync` function is another of the Angular testing utilities.
注意,在`it`的参数中,`async`被`faceAsync`替换。 注意,在`it`的参数中,`async`被`faceAsync`替换。
`fakeAsync`是另一Angular测试工具。 `fakeAsync`是另一Angular测试工具。
Like [async](#async-fn-in-it), it _takes_ a parameterless function and _returns_ a parameterless function Like [async](#async-fn-in-it), it _takes_ a parameterless function and _returns_ a parameterless function
which becomes the argument to the Jasmine `it` call. which becomes the argument to the Jasmine `it` call.
@ -1490,7 +1490,7 @@ a(href="#top").to-top 回到顶部
The `jasmine.done` technique, while discouraged, may become necessary when neither `async` nor `fakeAsync` The `jasmine.done` technique, while discouraged, may become necessary when neither `async` nor `fakeAsync`
can tolerate a particular asynchronous activity. That's rare but it happens. can tolerate a particular asynchronous activity. That's rare but it happens.
虽然不推荐使用`jasmine.done`技术,但是它可能在`async`和`fakeAsync`都无法容纳一特定的异步行为时,变得很有必要。这很少见,但是有可能发生。 虽然不推荐使用`jasmine.done`技术,但是它可能在`async`和`fakeAsync`都无法容纳一特定的异步行为时,变得很有必要。这很少见,但是有可能发生。
a(href="#top").to-top Back to top a(href="#top").to-top Back to top
a(href="#top").to-top 返回顶部 a(href="#top").to-top 返回顶部
@ -1506,7 +1506,7 @@ a(href="#top").to-top 返回顶部
The `TestBed.createComponent` is a synchronous method. The `TestBed.createComponent` is a synchronous method.
It assumes that everything it could need is already in memory. It assumes that everything it could need is already in memory.
`TestBed.createComponent`时一同步的方法。它假设所有它需要的资源已经全部在内存。 `TestBed.createComponent`时一同步的方法。它假设所有它需要的资源已经全部在内存。
That has been true so far. That has been true so far.
Each tested component's `@Component` metadata has a `template` property specifying an _inline templates_. Each tested component's `@Component` metadata has a `template` property specifying an _inline templates_.
@ -1557,7 +1557,7 @@ a(href="#top").to-top 返回顶部
that hides the mechanics of asynchronous execution, just as it does when passed to an [_it_ test)(#async). that hides the mechanics of asynchronous execution, just as it does when passed to an [_it_ test)(#async).
注意`beforeEach`里面对`async`的调用。 注意`beforeEach`里面对`async`的调用。
`async`函数将测试代码安排到一个特殊的**异步测试区域**来运行,该区域隐藏了异步执行的细节,就像它被传递给一个[_it_ 测试)(#async)一样。 `async`函数将测试代码安排到一个特殊的**异步测试区域**来运行,该区域隐藏了异步执行的细节,就像它被传递给[_it_ 测试)(#async)一样。
#compile-components #compile-components
:marked :marked
@ -1676,7 +1676,7 @@ a(href="#top").to-top 返回顶部
A quick look at the `DashboardComponent` constructor discourages the first approach: A quick look at the `DashboardComponent` constructor discourages the first approach:
简单看看`DashbaordComponent`的构造函数就否决了第一方案: 简单看看`DashbaordComponent`的构造函数就否决了第一方案:
+makeExample('testing/ts/app/dashboard/dashboard.component.ts', 'ctor', 'app/dashboard/dashboard.component.ts (constructor)')(format='.') +makeExample('testing/ts/app/dashboard/dashboard.component.ts', 'ctor', 'app/dashboard/dashboard.component.ts (constructor)')(format='.')
:marked :marked
@ -1848,7 +1848,7 @@ a(href="#top").to-top 返回顶部
Will the `DashboardHeroComponent` work properly when properly data-bound to a host component? Will the `DashboardHeroComponent` work properly when properly data-bound to a host component?
在前面的方法中,测试本身扮演了宿主组件`DashbaordComponent`的角色。 在前面的方法中,测试本身扮演了宿主组件`DashbaordComponent`的角色。
挥之不去的疑虑仍然存在:当正常数据绑定到宿主组件时,`DashboardHeroComponent`还会正常工作吗? 挥之不去的疑虑仍然存在:当正常数据绑定到宿主组件时,`DashboardHeroComponent`还会正常工作吗?
Testing with the actual `DashboardComponent` host is doable but seems more trouble than its worth. Testing with the actual `DashboardComponent` host is doable but seems more trouble than its worth.
It's easier to emulate the `DashboardComponent` host with a _test host_ like this one: It's easier to emulate the `DashboardComponent` host with a _test host_ like this one:
@ -1919,67 +1919,114 @@ a(href="#top").to-top 返回顶部
:marked :marked
# Test a routed component # Test a routed component
# 测试带路由器的组件
Testing the actual `DashboardComponent` seemed daunting because it injects the `Router`. Testing the actual `DashboardComponent` seemed daunting because it injects the `Router`.
测试实际的`DashbaordComponent`似乎令人生畏,因为它注入了`Router`。
+makeExample('testing/ts/app/dashboard/dashboard.component.ts', 'ctor', 'app/dashboard/dashboard.component.ts (constructor)')(format='.') +makeExample('testing/ts/app/dashboard/dashboard.component.ts', 'ctor', 'app/dashboard/dashboard.component.ts (constructor)')(format='.')
:marked :marked
It also injects the `HeroService` but faking that is a [familiar story](#component-with-async-servic). It also injects the `HeroService` but faking that is a [familiar story](#component-with-async-servic).
The `Router` has a complicated API and is entwined with other services and application pre-conditions. The `Router` has a complicated API and is entwined with other services and application pre-conditions.
它同时还注入了`HeroService`,但是我们已经直到如何[伪造](#component-with-async-servic)它。
`Router`的API非常复杂并且它缠绕了其他服务和许多应用的先觉条件。
Fortunately, the `DashboardComponent` isn't doing much with the `Router` Fortunately, the `DashboardComponent` isn't doing much with the `Router`
幸运的是,`DashbaordComponent`没有使用`Router`做很多事情。
+makeExample('testing/ts/app/dashboard/dashboard.component.ts', 'goto-detail', 'app/dashboard/dashboard.component.ts (goToDetail)')(format='.') +makeExample('testing/ts/app/dashboard/dashboard.component.ts', 'goto-detail', 'app/dashboard/dashboard.component.ts (goToDetail)')(format='.')
:marked :marked
This is often the case. This is often the case.
As a rule you test the component, not the router, As a rule you test the component, not the router,
and care only if the component navigates with the right address under the given conditions. and care only if the component navigates with the right address under the given conditions.
Stubbing the router with a test implementation is an easy option. This should do the trick: Stubbing the router with a test implementation is an easy option. This should do the trick:
通常都是这样的。原则上,你测试的是组件,不是路由器,应该只关心在指定的条件下,组件是否导航到正确的地址。
用一个模拟类来替换路由器是一种简单的方案。下面的代码应该可以:
+makeExample('testing/ts/app/dashboard/dashboard.component.spec.ts', 'router-stub', 'app/dashboard/dashboard.component.spec.ts (Router Stub)')(format='.') +makeExample('testing/ts/app/dashboard/dashboard.component.spec.ts', 'router-stub', 'app/dashboard/dashboard.component.spec.ts (Router Stub)')(format='.')
:marked :marked
Now we setup the testing module with the test stubs for the `Router` and `HeroService` and Now we setup the testing module with the test stubs for the `Router` and `HeroService` and
create a test instance of the `DashbaordComponent` for subsequent testing. create a test instance of the `DashbaordComponent` for subsequent testing.
现在我们来利用`Router`和`HeroService`的模拟类来配置测试模块,并为接下来的测试创建一个`DashbaordComponent`的测试实例。
+makeExample('testing/ts/app/dashboard/dashboard.component.spec.ts', 'compile-and-create-body', 'app/dashboard/dashboard.component.spec.ts (compile and create)')(format='.') +makeExample('testing/ts/app/dashboard/dashboard.component.spec.ts', 'compile-and-create-body', 'app/dashboard/dashboard.component.spec.ts (compile and create)')(format='.')
:marked :marked
The following test clicks the displayed hero and confirms (with the help of a spy) that `Router.navigateByUrl` is called with the expected url. The following test clicks the displayed hero and confirms (with the help of a spy) that `Router.navigateByUrl` is called with the expected url.
下面的测试点击显示的英雄并利用spy来确认`Router.navigateByUrl`被调用了而且传进的url是所期待的值。
+makeExample('testing/ts/app/dashboard/dashboard.component.spec.ts', 'navigate-test', 'app/dashboard/dashboard.component.spec.ts (navigate test)')(format='.') +makeExample('testing/ts/app/dashboard/dashboard.component.spec.ts', 'navigate-test', 'app/dashboard/dashboard.component.spec.ts (navigate test)')(format='.')
#inject #inject
:marked :marked
## The _inject_ function ## The _inject_ function
## _inject_函数
Notice the `inject` function in the second `it` argument. Notice the `inject` function in the second `it` argument.
注意第二个`it`参数里面的`inject`函数。
+makeExample('testing/ts/app/dashboard/dashboard.component.spec.ts', 'inject')(format='.') +makeExample('testing/ts/app/dashboard/dashboard.component.spec.ts', 'inject')(format='.')
:marked :marked
The `inject` function is one of the Angular testing utilities. The `inject` function is one of the Angular testing utilities.
It injects services into the test function where you can alter, spy on, and manipulate them. It injects services into the test function where you can alter, spy on, and manipulate them.
`inject`函数是Angular测试工具之一。
它注入服务到测试函数,以供修改、监视和操纵。
The `inject` function has two parameters The `inject` function has two parameters
`inject`函数有两个参数:
1. an array of Angular dependency injection tokens 1. an array of Angular dependency injection tokens
1. 一列数组包含了Angular依赖注入令牌
1. a test function whose parameters correspond exactly to each item in the injection token array 1. a test function whose parameters correspond exactly to each item in the injection token array
1. 一个测试函数,它的参数与注入令牌数组里的每个项目严格的一一对应。
.callout.is-important .callout.is-important
header inject uses the TestBed Injector header inject uses the TestBed Injector
header 使用TestBed注入器来注入
:marked :marked
The `inject` function uses the current `TestBed` injector and can only return services provided at that level. The `inject` function uses the current `TestBed` injector and can only return services provided at that level.
It does not return services from component providers. It does not return services from component providers.
`inject`函数使用当前`TestBed`注入器,并且值返回这个级别提供的服务。
它不会返回组件提供商提供的服务。
:marked :marked
This example injects the `Router` from the current `TestBed` injector. This example injects the `Router` from the current `TestBed` injector.
That's fine for this test because the `Router` is (and must be) provided by the application root injector. That's fine for this test because the `Router` is (and must be) provided by the application root injector.
这个例子通过当前的`TestBed`注入器来注入`Router`。
对这个测试来说,这是没问题的,因为`Router`是(也必须是)由应用的根注入器来提供。
If you need a service provided by the component's _own_ injector, call `fixture.debugElement.injector.get` instead: If you need a service provided by the component's _own_ injector, call `fixture.debugElement.injector.get` instead:
如果你需要组件自己的注入器提供的服务,调用`fixture.debugElement.injector.get`
+makeExample('testing/ts/app/welcome.component.spec.ts', 'injected-service', 'Component\'s injector')(format='.') +makeExample('testing/ts/app/welcome.component.spec.ts', 'injected-service', 'Component\'s injector')(format='.')
.alert.is-important .alert.is-important
:marked :marked
Use the component's own injector to get the service actually injected into the component. Use the component's own injector to get the service actually injected into the component.
使用组件自己的注入器来获取实际注入到组件的服务。
:marked :marked
The `inject` function closes the current `TestBed` instance to further configuration. The `inject` function closes the current `TestBed` instance to further configuration.
You cannot call any more `TestBed` configuration methods, not `configureTestModule` You cannot call any more `TestBed` configuration methods, not `configureTestModule`
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.
`inject`函数关闭当前`TestBed`实例,使它无法再被配置。
你不能再调用任何`TestBed`配置方法、`configureTestModule`或者任何`override...`方法,否则`TestBed`将抛出一个错误。
.alert.is-important .alert.is-important
:marked :marked
Do not configure the `TestBed` after calling `inject`. Do not configure the `TestBed` after calling `inject`.
不要再调用`inject`以后再试图配置`TestBed`。
a(href="#top").to-top Back to top a(href="#top").to-top Back to top
a(href="#top").to-top 回到顶部
.l-hr .l-hr
@ -1987,17 +2034,29 @@ a(href="#top").to-top Back to top
:marked :marked
# Test a routed component with parameters # Test a routed component with parameters
# 测试一个带有路由和路由参数的组件
Clicking a _Dashboard_ hero triggers navigation to `heroes/:id` where `:id` Clicking a _Dashboard_ hero triggers navigation to `heroes/:id` where `:id`
is a route parameter whose value is the `id` of the hero to edit. is a route parameter whose value is the `id` of the hero to edit.
That URL matches a route to the `HeroDetailComponent`. That URL matches a route to the `HeroDetailComponent`.
点击一个**Dashboard**英雄触发导航到`heros/:id`,其中`:id`是一个路由参数,它的值是进行编辑的英雄的`id`。
这个URL匹配到`HeroDetailComponent`的路由。
The router pushes the `:id` token value into the `ActivatedRoute.params` _Observable_ property, The router pushes the `:id` token value into the `ActivatedRoute.params` _Observable_ property,
Angular injects the `ActivatedRoute` into the `HeroDetailComponent`, Angular injects the `ActivatedRoute` into the `HeroDetailComponent`,
and the component extracts the `id` so it can fetch the corresponding hero via the `HeroDetailService`. and the component extracts the `id` so it can fetch the corresponding hero via the `HeroDetailService`.
Here's the `HeroDetailComponent` constructor: Here's the `HeroDetailComponent` constructor:
路由器将`:id`令牌的值推送到`ActivatedRoute.params`**可观察**属性里,
Angular注入`ActivatedRoute`到`HeroDetailComponent`中,
然后组件提取`id`,这样它就可以通过`HeroDetailServide`获取相应的英雄。
下面是`HeroDetailComponent`的构造函数:
+makeExample('testing/ts/app/hero/hero-detail.component.ts', 'ctor', 'app/hero/hero-detail.component.ts (constructor)')(format='.') +makeExample('testing/ts/app/hero/hero-detail.component.ts', 'ctor', 'app/hero/hero-detail.component.ts (constructor)')(format='.')
:marked :marked
`HeroDetailComponent` listens for changes to the `ActivatedRoute.params` in its `ngOnInit` method. `HeroDetailComponent` listens for changes to the `ActivatedRoute.params` in its `ngOnInit` method.
`HeroDetailComponent`在它的`ngOnInit`方法中监听`ActivatedRoute.params`的变化。
+makeExample('testing/ts/app/hero/hero-detail.component.ts', 'ng-on-init', 'app/hero/hero-detail.component.ts (ngOnInit)')(format='.') +makeExample('testing/ts/app/hero/hero-detail.component.ts', 'ng-on-init', 'app/hero/hero-detail.component.ts (ngOnInit)')(format='.')
.l-sub-section .l-sub-section
:marked :marked
@ -2005,49 +2064,88 @@ a(href="#top").to-top Back to top
and then chains a `forEach` operator to subscribes to `id`-changing events. and then chains a `forEach` operator to subscribes to `id`-changing events.
The `id` changes every time the user navigates to a different hero. The `id` changes every time the user navigates to a different hero.
`route.params`之后的表达式链接了一个**可观察**操作符,它从`params`中提取`id`,然后链接一个`forEach`操作符来订阅`id`变化事件。
每次`id`变化时,用户被导航到不同的英雄。
The `forEach` passes the new `id` value to the component's `getHero` method (not shown) The `forEach` passes the new `id` value to the component's `getHero` method (not shown)
which fetches a hero and sets the component's `hero` property. which fetches a hero and sets the component's `hero` property.
If the`id` parameter is missing, the `pluck` operator fails and the `catch` treats failure as a request to edit a new hero. If the`id` parameter is missing, the `pluck` operator fails and the `catch` treats failure as a request to edit a new hero.
`forEach`将新的`id`值传递到组件的`getHero`方法(这里没有列出来),它获取一个英雄并将它赋值到组件的`hero`属性。
如果`id`参数无效,`pluck`操作符就会失败,`catch`将失败当作创建一个新英雄来处理。
The [Router](router.html#route-parameters) chapter covers `ActivatedRoute.params` in more detail. The [Router](router.html#route-parameters) chapter covers `ActivatedRoute.params` in more detail.
[路由器](router.html#route-parameters)章更详尽的讲述了`ActivatedRoute.params`。
:marked :marked
A test can explore how the `HeroDetailComponent` responds to different `id` parameter values A test can explore how the `HeroDetailComponent` responds to different `id` parameter values
by manipulating the `ActivatedRoute` injected into the component's constructor. by manipulating the `ActivatedRoute` injected into the component's constructor.
通过操纵被注入到组件构造函数的`ActivatedRoute`服务,测试可以探索`HeroDetailComponent`是如何对不同的`id`参数值作出响应的。
By now you know how to stub the `Router` and a data service. By now you know how to stub the `Router` and a data service.
Stubbing the `ActivatedRoute` would follow the same pattern except for a complication: Stubbing the `ActivatedRoute` would follow the same pattern except for a complication:
the `ActivatedRoute.params` is an _Observable_. the `ActivatedRoute.params` is an _Observable_.
现在,你已经直到如何伪造`Router`和一个数据服务。
伪造`ActivatedRoute`遵循类似的模式,但是有一个额外枝节:`ActivatedRoute.params`是一个**可观察对象**。
#stub-observable #stub-observable
:marked :marked
### _Observable_ test double ### _Observable_ test double
### **可观察对象**的测试复制品
The `hero-detail.component.spec.ts` relies on an `ActivatedRouteStub` to set `ActivatedRoute.params` values for each test. The `hero-detail.component.spec.ts` relies on an `ActivatedRouteStub` to set `ActivatedRoute.params` values for each test.
This is a cross-application, re-usable _test helper class_. This is a cross-application, re-usable _test helper class_.
We recommend locating such helpers in a `testing` folder sibling to the `app` folder. We recommend locating such helpers in a `testing` folder sibling to the `app` folder.
This sample keeps `ActivatedRouteStub` in `testing/router-stubs.ts`: This sample keeps `ActivatedRouteStub` in `testing/router-stubs.ts`:
`hero-detail.component.spec.ts`依赖一个`ActivatedRouteStub`来为每个测试设置`ActivatedRoute.params`值。
它是一个跨应用、可复用的**测试辅助类**。
我们建议将这样的辅助类放到`app`目录下的一个名为`testing`的目录。
本例把`ActivatedRouteStub`放到`testing/router-stubs.ts`
+makeExample('testing/ts/testing/router-stubs.ts', 'activated-route-stub', 'testing/router-stubs.ts (ActivatedRouteStub)')(format='.') +makeExample('testing/ts/testing/router-stubs.ts', 'activated-route-stub', 'testing/router-stubs.ts (ActivatedRouteStub)')(format='.')
:marked :marked
Notable features of this stub: Notable features of this stub:
这个类有下列值得注意的特征:
* The stub implements only two of the `ActivatedRoute` capabilities: `params` and `snapshot.params`. * The stub implements only two of the `ActivatedRoute` capabilities: `params` and `snapshot.params`.
* 它只实现`ActivatedRoute`的两个功能:`params`和`snapshot.params`。
* <a href="https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/behaviorsubject.md" target="_blank">_BehaviorSubject_</a> * <a href="https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/behaviorsubject.md" target="_blank">_BehaviorSubject_</a>
drives the stub's `params` _Observable_ and returns the same value to every `params` subscriber until it's given a new value. drives the stub's `params` _Observable_ and returns the same value to every `params` subscriber until it's given a new value.
* <a href="https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/behaviorsubject.md" target="_blank">_BehaviorSubject_</a>
驱使它的`params`可观察对象,并为每个`params`的订阅者返回同样的值,直到它接受到新值。
* The `HeroDetailComponent` chain its expressions to this stub `params` _Observable_ which is now under the tester's control. * The `HeroDetailComponent` chain its expressions to this stub `params` _Observable_ which is now under the tester's control.
* `HeroDetailComponent`链接它的表达式到它的`params`可观察对象,该对象现在被测试者所控制。
* Setting the `testParams` property causes the `subject` to push the assigned value into `params`. * Setting the `testParams` property causes the `subject` to push the assigned value into `params`.
That triggers the `HeroDetailComponent` _params_ subscription, described above, in the same way that navigation does. That triggers the `HeroDetailComponent` _params_ subscription, described above, in the same way that navigation does.
* 设置`testParams`属性导致`subject`将指定的值推送进`params`。
它触发上面描述过的`HeroDetailComponent`的`params`订阅,和导航的方式一样。
* Setting the `testParams` property also updates the stub's internal value for the `snapshot` property to return. * Setting the `testParams` property also updates the stub's internal value for the `snapshot` property to return.
* 设置`testParams`属性同时更新它内部值,用于`snapshot`属性的返回。
.l-sub-section(style="margin-left:30px") .l-sub-section(style="margin-left:30px")
:marked :marked
The [_snapshot_](router.html#snapshot "Router Chapter: snapshot") is another popular way for components to consume route parameters. The [_snapshot_](router.html#snapshot "Router Chapter: snapshot") is another popular way for components to consume route parameters.
[_snapshot_](router.html#snapshot "Router Chapter: snapshot")是组件使用路由参数的另一种流行的方法。
.callout.is-helpful .callout.is-helpful
:marked :marked
The router stubs in this chapter are meant to inspire you. Create your own stubs to fit your testing needs. The router stubs in this chapter are meant to inspire you. Create your own stubs to fit your testing needs.
本章的路由器模拟类是为了给你灵感。创建你自己的模拟类,以适合你的测试需求。
#observable-tests #observable-tests
:marked :marked
### _Observable_ tests ### _Observable_ tests