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,21 +4590,25 @@ 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. | ||||||
| 
 | 
 | ||||||
| `ComponentFixture`的属性和方法提供了对组件、它的DOM和它的Angular环境方面的访问。 | `ComponentFixture` 的属性和方法提供了对组件、它的 DOM 和它的 Angular 环境方面的访问。 | ||||||
| 
 | 
 | ||||||
| {@a component-fixture-properties} | {@a component-fixture-properties} | ||||||
| 
 | 
 | ||||||
| #### _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