修订完testing
This commit is contained in:
parent
4b7daad85b
commit
04c77dc05a
@ -8,13 +8,13 @@
|
|||||||
"prerelease": [
|
"prerelease": [
|
||||||
"local"
|
"local"
|
||||||
],
|
],
|
||||||
"build": "sha.3271832",
|
"build": "sha.4b7daad",
|
||||||
"version": "4.0.0-local",
|
"version": "4.0.0-local",
|
||||||
"codeName": "snapshot",
|
"codeName": "snapshot",
|
||||||
"isSnapshot": true,
|
"isSnapshot": true,
|
||||||
"full": "4.0.0-local+sha.3271832",
|
"full": "4.0.0-local+sha.4b7daad",
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"commitSHA": "32718328dc513900bdec26f78bf7b7547d1703d8"
|
"commitSHA": "4b7daad85b1fd6c97002652c840b560291bfce2b"
|
||||||
},
|
},
|
||||||
"sections": []
|
"sections": []
|
||||||
}
|
}
|
@ -1200,7 +1200,6 @@ a(id="find-parent")
|
|||||||
|
|
||||||
a #known-parent
|
a #known-parent
|
||||||
:marked
|
:marked
|
||||||
|
|
||||||
### Find a parent component of known type
|
### Find a parent component of known type
|
||||||
|
|
||||||
### 找到已知类型的父组件
|
### 找到已知类型的父组件
|
||||||
@ -1214,7 +1213,9 @@ a #known-parent
|
|||||||
在下面的例子中,父组件`AlexComponent`有几个子组件,包括`CathyComponent`:
|
在下面的例子中,父组件`AlexComponent`有几个子组件,包括`CathyComponent`:
|
||||||
|
|
||||||
a(id='alex')
|
a(id='alex')
|
||||||
|
|
||||||
+makeExample('cb-dependency-injection/ts/src/app/parent-finder.component.ts','alex-1','parent-finder.component.ts (AlexComponent v.1)')(format='.')
|
+makeExample('cb-dependency-injection/ts/src/app/parent-finder.component.ts','alex-1','parent-finder.component.ts (AlexComponent v.1)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
*Cathy* reports whether or not she has access to *Alex*
|
*Cathy* reports whether or not she has access to *Alex*
|
||||||
after injecting an `AlexComponent` into her constructor:
|
after injecting an `AlexComponent` into her constructor:
|
||||||
|
@ -8,13 +8,13 @@
|
|||||||
"prerelease": [
|
"prerelease": [
|
||||||
"local"
|
"local"
|
||||||
],
|
],
|
||||||
"build": "sha.3271832",
|
"build": "sha.4b7daad",
|
||||||
"version": "4.0.0-local",
|
"version": "4.0.0-local",
|
||||||
"codeName": "snapshot",
|
"codeName": "snapshot",
|
||||||
"isSnapshot": true,
|
"isSnapshot": true,
|
||||||
"full": "4.0.0-local+sha.3271832",
|
"full": "4.0.0-local+sha.4b7daad",
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"commitSHA": "32718328dc513900bdec26f78bf7b7547d1703d8"
|
"commitSHA": "4b7daad85b1fd6c97002652c840b560291bfce2b"
|
||||||
},
|
},
|
||||||
"sections": []
|
"sections": []
|
||||||
}
|
}
|
@ -81,7 +81,9 @@ a#toc
|
|||||||
[内置结构型指令](#structural-directives)
|
[内置结构型指令](#structural-directives)
|
||||||
|
|
||||||
* [NgIf](#ngIf)
|
* [NgIf](#ngIf)
|
||||||
|
|
||||||
* [NgFor](#ngFor)
|
* [NgFor](#ngFor)
|
||||||
|
|
||||||
* [Template input variables](#template-input-variables)
|
* [Template input variables](#template-input-variables)
|
||||||
|
|
||||||
[模板输入变量](#template-input-variables)
|
[模板输入变量](#template-input-variables)
|
||||||
@ -124,8 +126,7 @@ a#html
|
|||||||
:marked
|
:marked
|
||||||
## HTML in templates
|
## HTML in templates
|
||||||
|
|
||||||
|
## 模板中的HTML
|
||||||
## HTML
|
|
||||||
|
|
||||||
HTML is the language of the Angular template.
|
HTML is the language of the Angular template.
|
||||||
Almost all HTML syntax is valid template syntax.
|
Almost all HTML syntax is valid template syntax.
|
||||||
@ -214,7 +215,7 @@ a#interpolation
|
|||||||
|
|
||||||
表面上看,我们在元素标签之间插入了结果和对标签的属性进行了赋值。
|
表面上看,我们在元素标签之间插入了结果和对标签的属性进行了赋值。
|
||||||
这样思考起来很方便,并且这个误解很少给我们带来麻烦。
|
这样思考起来很方便,并且这个误解很少给我们带来麻烦。
|
||||||
但严格来讲,这是不对的。插值表达式是一个特殊的语法,Angular 把它转换成了[属性绑定](#property-binding),后面将会解释这一点。
|
但严格来讲,这是不对的。插值表达式是一个特殊的语法,Angular 把它转换成了[属性绑定](#property-binding),[后面](#property-binding-or-interpolation-)将会解释这一点。
|
||||||
|
|
||||||
But first, let's take a closer look at template expressions and statements.
|
But first, let's take a closer look at template expressions and statements.
|
||||||
|
|
||||||
@ -329,7 +330,9 @@ a#expression-context
|
|||||||
a(href="#toc") back to top
|
a(href="#toc") back to top
|
||||||
a(href="#toc") 回到顶部
|
a(href="#toc") 回到顶部
|
||||||
|
|
||||||
a#no-side-effectsa#expression-guidelines
|
a#no-side-effects
|
||||||
|
a#expression-guidelines
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Expression guidelines
|
### Expression guidelines
|
||||||
|
|
||||||
@ -700,8 +703,13 @@ table
|
|||||||
:marked
|
:marked
|
||||||
You still create a structure and initialize attribute values this way in Angular templates.
|
You still create a structure and initialize attribute values this way in Angular templates.
|
||||||
|
|
||||||
在 Angular 模板中,我们仍使用同样的方式来创建结构和初始化 attribute 值。Then you learn to create new elements with components that encapsulate HTML
|
在 Angular 模板中,我们仍使用同样的方式来创建结构和初始化 attribute 值。
|
||||||
and drop them into templates as if they were native HTML elements.然后,用封装了 HTML 的组件创建新元素,并把它们当作原生 HTML 元素在模板中使用。
|
|
||||||
|
Then you learn to create new elements with components that encapsulate HTML
|
||||||
|
and drop them into templates as if they were native HTML elements.
|
||||||
|
|
||||||
|
然后,用封装了 HTML 的组件创建新元素,并把它们当作原生 HTML 元素在模板中使用。
|
||||||
|
|
||||||
+makeExample('template-syntax/ts/src/app/app.component.html', 'hero-detail-1')(format=".")
|
+makeExample('template-syntax/ts/src/app/app.component.html', 'hero-detail-1')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
@ -823,12 +831,17 @@ table
|
|||||||
|
|
||||||
.callout.is-helpful
|
.callout.is-helpful
|
||||||
header A world without attributes
|
header A world without attributes
|
||||||
|
|
||||||
header 没有 attribute 的世界
|
header 没有 attribute 的世界
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
In the world of Angular, the only role of attributes is to initialize element and directive state.
|
In the world of Angular, the only role of attributes is to initialize element and directive state.
|
||||||
When you write a data binding, you're dealing exclusively with properties and eventsof the target object.
|
When you write a data binding, you're dealing exclusively with properties and eventsof the target object.
|
||||||
HTML attributes effectively disappear.在 Angular 的世界中,attribute 唯一的作用是用来初始化元素和指令的状态。
|
HTML attributes effectively disappear.
|
||||||
|
|
||||||
|
在 Angular 的世界中,attribute 唯一的作用是用来初始化元素和指令的状态。
|
||||||
当进行数据绑定时,只是在与元素和指令的 property 和事件打交道,而 attribute 就完全靠边站了。
|
当进行数据绑定时,只是在与元素和指令的 property 和事件打交道,而 attribute 就完全靠边站了。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
With this model firmly in mind, read on to learn about binding targets.
|
With this model firmly in mind, read on to learn about binding targets.
|
||||||
|
|
||||||
@ -943,8 +956,11 @@ a#property-binding
|
|||||||
当要把视图元素的属性 (property) 设置为[模板表达式](#template-expressions)时,就要写模板的**属性 (property) 绑定**。
|
当要把视图元素的属性 (property) 设置为[模板表达式](#template-expressions)时,就要写模板的**属性 (property) 绑定**。
|
||||||
|
|
||||||
The most common property binding sets an element property to a component property value. An example is
|
The most common property binding sets an element property to a component property value. An example is
|
||||||
binding the `src` property of an image element to a component's `heroImageUrl` property:最常用的属性绑定是把元素属性设置为组件属性的值。
|
binding the `src` property of an image element to a component's `heroImageUrl` property:
|
||||||
|
|
||||||
|
最常用的属性绑定是把元素属性设置为组件属性的值。
|
||||||
下面这个例子中,image 元素的`src`属性会被绑定到组件的`heroImageUrl`属性上:
|
下面这个例子中,image 元素的`src`属性会被绑定到组件的`heroImageUrl`属性上:
|
||||||
|
|
||||||
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-1')(format=".")
|
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-1')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
@ -1043,9 +1059,12 @@ a#property-binding
|
|||||||
:marked
|
:marked
|
||||||
Technically, Angular is matching the name to a directive [input](#inputs-outputs),
|
Technically, Angular is matching the name to a directive [input](#inputs-outputs),
|
||||||
one of the property names listed in the directive's `inputs` array or a property decorated with `@Input()`.
|
one of the property names listed in the directive's `inputs` array or a property decorated with `@Input()`.
|
||||||
Such inputs map to the directive's own properties.严格来说,Angular 正在匹配指令的[输入属性](#inputs-outputs)的名字。
|
Such inputs map to the directive's own properties.
|
||||||
|
|
||||||
|
严格来说,Angular 正在匹配指令的[输入属性](#inputs-outputs)的名字。
|
||||||
这个名字是指令的`inputs`数组中所列的名字,或者是带有`@Input()`装饰器的属性。
|
这个名字是指令的`inputs`数组中所列的名字,或者是带有`@Input()`装饰器的属性。
|
||||||
这些输入属性被映射为指令自己的属性。
|
这些输入属性被映射为指令自己的属性。
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
If the name fails to match a property of a known directive or element, Angular reports an “unknown directive” error.
|
If the name fails to match a property of a known directive or element, Angular reports an “unknown directive” error.
|
||||||
|
|
||||||
@ -1089,7 +1108,12 @@ a#property-binding
|
|||||||
模板表达式应该返回目标属性所需类型的值。
|
模板表达式应该返回目标属性所需类型的值。
|
||||||
如果目标属性想要个字符串,就返回字符串。
|
如果目标属性想要个字符串,就返回字符串。
|
||||||
如果目标属性想要个数字,就返回数字。
|
如果目标属性想要个数字,就返回数字。
|
||||||
如果目标属性想要个对象,就返回对象。The `hero` property of the `HeroDetail` component expects a `Hero` object, which is exactly what you're sending in the property binding:`HeroDetail`组件的`hero`属性想要一个`Hero`对象,那就在属性绑定中精确地给它一个`Hero`对象:
|
如果目标属性想要个对象,就返回对象。
|
||||||
|
|
||||||
|
The `hero` property of the `HeroDetail` component expects a `Hero` object, which is exactly what you're sending in the property binding:
|
||||||
|
|
||||||
|
`HeroDetail`组件的`hero`属性想要一个`Hero`对象,那就在属性绑定中精确地给它一个`Hero`对象:
|
||||||
|
|
||||||
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-4')(format=".")
|
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-4')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
@ -1271,7 +1295,10 @@ code-example(language="html").
|
|||||||
<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
|
<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
And you get this error:会得到这个错误:
|
And you get this error:
|
||||||
|
|
||||||
|
会得到这个错误:
|
||||||
|
|
||||||
code-example(format="nocode").
|
code-example(format="nocode").
|
||||||
Template parse errors:
|
Template parse errors:
|
||||||
Can't bind to 'colspan' since it isn't a known native property
|
Can't bind to 'colspan' since it isn't a known native property
|
||||||
|
@ -154,6 +154,7 @@ a#top
|
|||||||
* <live-example embedded-style>The sample application to be tested</live-example>.
|
* <live-example embedded-style>The sample application to be tested</live-example>.
|
||||||
* <live-example plnkr="app-specs" embedded-style>All specs that test the sample application</live-example>.
|
* <live-example plnkr="app-specs" embedded-style>All specs that test the sample application</live-example>.
|
||||||
* <live-example plnkr="bag-specs" embedded-style>A grab bag of additional specs</live-example>.
|
* <live-example plnkr="bag-specs" embedded-style>A grab bag of additional specs</live-example>.
|
||||||
|
|
||||||
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 回到顶部
|
||||||
|
|
||||||
@ -206,7 +207,9 @@ a#tools-and-tech
|
|||||||
|
|
||||||
You can write and run Angular tests with a variety of tools and technologies.
|
You can write and run Angular tests with a variety of tools and technologies.
|
||||||
This guide describes specific choices that are known to work well.
|
This guide describes specific choices that are known to work well.
|
||||||
|
|
||||||
你可以用多种工具和技术来编写和运行Angular测试程序。本章介绍了一些大家已经知道能良好工作的选择。
|
你可以用多种工具和技术来编写和运行Angular测试程序。本章介绍了一些大家已经知道能良好工作的选择。
|
||||||
|
|
||||||
table(width="100%")
|
table(width="100%")
|
||||||
col(width="20%")
|
col(width="20%")
|
||||||
col(width="80%")
|
col(width="80%")
|
||||||
@ -359,9 +362,11 @@ a#run-karma
|
|||||||
### Run with karma
|
### Run with karma
|
||||||
|
|
||||||
### 运行Karma
|
### 运行Karma
|
||||||
|
|
||||||
Compile and run it in karma from the command line using the following command:
|
Compile and run it in karma from the command line using the following command:
|
||||||
|
|
||||||
使用下面的命令从命令行中编译并在`Karma`中运行上面的测试程序。
|
使用下面的命令从命令行中编译并在`Karma`中运行上面的测试程序。
|
||||||
|
|
||||||
code-example(format="." language="bash").
|
code-example(format="." language="bash").
|
||||||
npm test
|
npm test
|
||||||
:marked
|
:marked
|
||||||
@ -608,8 +613,10 @@ a#component-fixture
|
|||||||
|
|
||||||
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.
|
||||||
Its `By.css` static method produces a
|
Its `By.css` static method produces a
|
||||||
@ -696,14 +703,19 @@ a#auto-detect-changes
|
|||||||
Some testers prefer that the Angular test environment run change detection automatically.
|
Some testers prefer that the Angular test environment run change detection automatically.
|
||||||
That's possible by configuring the `TestBed` with the `ComponentFixtureAutoDetect` provider .
|
That's possible by configuring the `TestBed` with the `ComponentFixtureAutoDetect` provider .
|
||||||
First import itfrom the testing utility library :
|
First import itfrom the testing utility library :
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/banner.component.detect-changes.spec.ts', 'import-ComponentFixtureAutoDetect', 'src/app/banner.component.detect-changes.spec.ts (import)')(format='.')
|
+makeExample('testing/ts/src/app/banner.component.detect-changes.spec.ts', 'import-ComponentFixtureAutoDetect', 'src/app/banner.component.detect-changes.spec.ts (import)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Then add it to the `providers` array of the testing module configuration:
|
Then add it to the `providers` array of the testing module configuration:
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/banner.component.detect-changes.spec.ts', 'auto-detect', 'src/app/banner.component.detect-changes.spec.ts (AutoDetect)')(format='.')
|
+makeExample('testing/ts/src/app/banner.component.detect-changes.spec.ts', 'auto-detect', 'src/app/banner.component.detect-changes.spec.ts (AutoDetect)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Here are three tests that illustrate how automatic change detection works.
|
Here are three tests that illustrate how automatic change detection works.
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/banner.component.detect-changes.spec.ts', 'auto-detect-tests', 'src/app/banner.component.detect-changes.spec.ts (AutoDetect Tests)')(format='.')
|
+makeExample('testing/ts/src/app/banner.component.detect-changes.spec.ts', 'auto-detect-tests', 'src/app/banner.component.detect-changes.spec.ts (AutoDetect Tests)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The first test shows the benefit of automatic change detection.
|
The first test shows the benefit of automatic change detection.
|
||||||
|
|
||||||
@ -854,6 +866,7 @@ a#component-with-dependency
|
|||||||
## Test a component with a dependency
|
## Test a component with a dependency
|
||||||
|
|
||||||
## 测试有依赖的组件
|
## 测试有依赖的组件
|
||||||
|
|
||||||
Components often have service dependencies.
|
Components often have service dependencies.
|
||||||
|
|
||||||
The `WelcomeComponent` displays a welcome message to the logged in user.
|
The `WelcomeComponent` displays a welcome message to the logged in user.
|
||||||
@ -870,11 +883,14 @@ a#component-with-dependency
|
|||||||
`WelcomeComponent`有与服务进行交互的决策逻辑,这样的逻辑让这个组件值得测试。下面是spec文件的测试模块配置,`src/app/welcome.component.spec.ts`:
|
`WelcomeComponent`有与服务进行交互的决策逻辑,这样的逻辑让这个组件值得测试。下面是spec文件的测试模块配置,`src/app/welcome.component.spec.ts`:
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/welcome.component.spec.ts', 'config-test-module', 'src/app/welcome.component.spec.ts')(format='.')
|
+makeExample('testing/ts/src/app/welcome.component.spec.ts', 'config-test-module', 'src/app/welcome.component.spec.ts')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
This time, in addition to declaring the _component-under-test_,
|
This time, in addition to declaring the _component-under-test_,
|
||||||
the configuration adds a `UserService` provider to the `providers` list.
|
the configuration adds a `UserService` provider to the `providers` list.
|
||||||
But not the real `UserService`.
|
But not the real `UserService`.
|
||||||
|
|
||||||
这次,在测试配置里不但声明了被测试的组件,而且在`providers`数组中添加了`UserService`依赖。但不是真实的`UserService`。
|
这次,在测试配置里不但声明了被测试的组件,而且在`providers`数组中添加了`UserService`依赖。但不是真实的`UserService`。
|
||||||
|
|
||||||
a#service-test-doubles
|
a#service-test-doubles
|
||||||
:marked
|
:marked
|
||||||
### Provide service test doubles
|
### Provide service test doubles
|
||||||
@ -1051,9 +1067,14 @@ a#component-with-async-service
|
|||||||
It is sufficient to see within `ngOnInit` that `twainService.getQuote` returns a promise, which means it is asynchronous.
|
It is sufficient to see within `ngOnInit` that `twainService.getQuote` returns a promise, which means it is asynchronous.
|
||||||
|
|
||||||
`TwainService`的实现细节现在并不重要。
|
`TwainService`的实现细节现在并不重要。
|
||||||
`ngOnInit`的`twainService.getQuote`返回承诺,所以显然它是异步的。In general, tests should not make calls to remote servers.
|
`ngOnInit`的`twainService.getQuote`返回承诺,所以显然它是异步的。
|
||||||
They should emulate such calls. The setup in this `src/app/shared/twain.component.spec.ts` shows one way to do that: 一般来讲,测试程序不应该向远程服务器发请求。
|
|
||||||
|
In general, tests should not make calls to remote servers.
|
||||||
|
They should emulate such calls. The setup in this `src/app/shared/twain.component.spec.ts` shows one way to do that:
|
||||||
|
|
||||||
|
一般来讲,测试程序不应该向远程服务器发请求。
|
||||||
它们应该仿真这样的请求。`src/app/shared/twain.component.spec.ts`里的配置是其中一种伪造方法:
|
它们应该仿真这样的请求。`src/app/shared/twain.component.spec.ts`里的配置是其中一种伪造方法:
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/shared/twain.component.spec.ts', 'setup', 'src/app/shared/twain.component.spec.ts (setup)')(format='.')
|
+makeExample('testing/ts/src/app/shared/twain.component.spec.ts', 'setup', 'src/app/shared/twain.component.spec.ts (setup)')(format='.')
|
||||||
|
|
||||||
a#service-spy
|
a#service-spy
|
||||||
@ -1070,6 +1091,7 @@ a#service-spy
|
|||||||
但是与其伪造服务对象,它注入了真实的服务(参见测试模块的`providers`),并用Jasmine的`spy`替换关键的`getQuote`方法。
|
但是与其伪造服务对象,它注入了真实的服务(参见测试模块的`providers`),并用Jasmine的`spy`替换关键的`getQuote`方法。
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/shared/twain.component.spec.ts', 'spy')(format='.')
|
+makeExample('testing/ts/src/app/shared/twain.component.spec.ts', 'spy')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
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 does not contact the server.
|
The spy bypasses the actual `getQuote` method and therefore does not contact the server.
|
||||||
@ -1109,8 +1131,10 @@ a#sync-tests
|
|||||||
|
|
||||||
Neither test can prove that a value from the service is displayed.
|
Neither test can prove that a value from the service is displayed.
|
||||||
The quote itself has not arrived, despite the fact that the spy returns a resolved promise.
|
The quote itself has not arrived, despite the fact that the spy returns a resolved promise.
|
||||||
|
|
||||||
两者都不能证明被显示的值是服务提供的。
|
两者都不能证明被显示的值是服务提供的。
|
||||||
虽然spy返回了解析的承诺,名言本身还没有到来。
|
虽然spy返回了解析的承诺,名言本身还没有到来。
|
||||||
|
|
||||||
This test must wait at least one full turn of the JavaScript engine before the
|
This test must wait at least one full turn of the JavaScript engine before the
|
||||||
value becomes available. The test must become _asynchronous_.
|
value becomes available. The test must become _asynchronous_.
|
||||||
|
|
||||||
@ -1120,7 +1144,7 @@ a#async
|
|||||||
:marked
|
:marked
|
||||||
### The _async_ function in _it_
|
### The _async_ function in _it_
|
||||||
|
|
||||||
## **it**里的**async**函数方法
|
### **it**里的**async**函数方法
|
||||||
|
|
||||||
Notice the `async` in the third test.
|
Notice the `async` in the third test.
|
||||||
|
|
||||||
@ -1149,7 +1173,7 @@ a#when-stable
|
|||||||
:marked
|
:marked
|
||||||
### _whenStable_
|
### _whenStable_
|
||||||
|
|
||||||
## **whenStable**
|
### **whenStable**
|
||||||
|
|
||||||
The test must wait for the `getQuote` promise to resolve in the next turn of the JavaScript engine.
|
The test must wait for the `getQuote` promise to resolve in the next turn of the JavaScript engine.
|
||||||
|
|
||||||
@ -1184,7 +1208,7 @@ a#fake-async
|
|||||||
:marked
|
:marked
|
||||||
### The _fakeAsync_ function
|
### The _fakeAsync_ function
|
||||||
|
|
||||||
## **fakeAsync**函数方法
|
### **fakeAsync**函数方法
|
||||||
|
|
||||||
The fourth test verifies the same component behavior in a different way.
|
The fourth test verifies the same component behavior in a different way.
|
||||||
|
|
||||||
@ -1224,7 +1248,8 @@ a#tick
|
|||||||
:marked
|
:marked
|
||||||
### The _tick_ function
|
### The _tick_ function
|
||||||
|
|
||||||
## **tick**函数
|
### **tick**函数
|
||||||
|
|
||||||
The `tick` function is one of the Angular testing utilities and a companion to `fakeAsync`.
|
The `tick` function is one of the Angular testing utilities and a companion to `fakeAsync`.
|
||||||
You can only call it within a `fakeAsync` body.
|
You can only call it within a `fakeAsync` body.
|
||||||
|
|
||||||
@ -1252,6 +1277,7 @@ a#tick
|
|||||||
a#jasmine-done
|
a#jasmine-done
|
||||||
:marked
|
:marked
|
||||||
### _jasmine.done_
|
### _jasmine.done_
|
||||||
|
|
||||||
While the `async` and `fakeAsync` functions greatly
|
While the `async` and `fakeAsync` functions greatly
|
||||||
simplify Angular asynchronous testing,
|
simplify Angular asynchronous testing,
|
||||||
you can still fall back to the traditional Jasmine asynchronous testing technique.
|
you can still fall back to the traditional Jasmine asynchronous testing technique.
|
||||||
@ -1268,7 +1294,9 @@ a#jasmine-done
|
|||||||
Here is a `done` version of the previous two tests:
|
Here is a `done` version of the previous two tests:
|
||||||
|
|
||||||
下面是上面两个测试程序的`done`版本:
|
下面是上面两个测试程序的`done`版本:
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/shared/twain.component.spec.ts', 'done-test', 'src/app/shared/twain.component.spec.ts (done test)')(format='.')
|
+makeExample('testing/ts/src/app/shared/twain.component.spec.ts', 'done-test', 'src/app/shared/twain.component.spec.ts (done test)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Although there is no direct access to the `getQuote` promise inside `TwainComponent`,
|
Although there is no direct access to the `getQuote` promise inside `TwainComponent`,
|
||||||
the spy has direct access, which makes it possible to wait for `getQuote` to finish.
|
the spy has direct access, which makes it possible to wait for `getQuote` to finish.
|
||||||
@ -1293,6 +1321,7 @@ a#component-with-input-output
|
|||||||
## Test a component with inputs and outputs
|
## Test a component with inputs and outputs
|
||||||
|
|
||||||
## 测试带有导入inputs和导出outputs的组件
|
## 测试带有导入inputs和导出outputs的组件
|
||||||
|
|
||||||
A component with inputs and outputs typically appears inside the view template of a host component.
|
A component with inputs and outputs typically appears inside the view template of a host component.
|
||||||
The host uses a property binding to set the input property and an event binding to
|
The host uses a property binding to set the input property and an event binding to
|
||||||
listen to events raised by the output property.
|
listen to events raised by the output property.
|
||||||
@ -1322,12 +1351,15 @@ a#component-with-input-output
|
|||||||
:marked
|
:marked
|
||||||
The `DashboardHeroComponent` appears in an `*ngFor` repeater, which sets each component's `hero` input property
|
The `DashboardHeroComponent` appears in an `*ngFor` repeater, which sets each component's `hero` input property
|
||||||
to the looping value and listens for the component's `selected` event.
|
to the looping value and listens for the component's `selected` event.
|
||||||
|
|
||||||
`DashboardHeroComponent`在`*ngFor`循环中出现,设置每个组件的`hero`input属性到迭代的值,并监听组件的`selected`事件。
|
`DashboardHeroComponent`在`*ngFor`循环中出现,设置每个组件的`hero`input属性到迭代的值,并监听组件的`selected`事件。
|
||||||
|
|
||||||
Here's the component's definition:
|
Here's the component's definition:
|
||||||
|
|
||||||
下面是组件的定义:
|
下面是组件的定义:
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/dashboard/dashboard-hero.component.ts', 'component', 'src/app/dashboard/dashboard-hero.component.ts (component)')(format='.')
|
+makeExample('testing/ts/src/app/dashboard/dashboard-hero.component.ts', 'component', 'src/app/dashboard/dashboard-hero.component.ts (component)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
While testing a component this simple has little intrinsic value, it's worth knowing how.
|
While testing a component this simple has little intrinsic value, it's worth knowing how.
|
||||||
You can use one of these approaches:
|
You can use one of these approaches:
|
||||||
@ -1411,7 +1443,9 @@ a#dashboard-standalone
|
|||||||
|
|
||||||
它验证了英雄名字通过绑定被传递到模板了。这里有个额外步骤。模板将英雄名字传给Angular的`UpperCasePipe`,
|
它验证了英雄名字通过绑定被传递到模板了。这里有个额外步骤。模板将英雄名字传给Angular的`UpperCasePipe`,
|
||||||
所以测试程序必须使用大写名字来匹配元素的值:
|
所以测试程序必须使用大写名字来匹配元素的值:
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/dashboard/dashboard-hero.component.html')(format='.')
|
+makeExample('testing/ts/src/app/dashboard/dashboard-hero.component.html')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
.alert.is-helpful
|
.alert.is-helpful
|
||||||
:marked
|
:marked
|
||||||
@ -1437,12 +1471,16 @@ a#dashboard-standalone
|
|||||||
The `heroEl` is a `DebugElement` that represents the hero `<div>`.
|
The `heroEl` is a `DebugElement` that represents the hero `<div>`.
|
||||||
The test calls `triggerEventHandler` with the "click" event name.
|
The test calls `triggerEventHandler` with the "click" event name.
|
||||||
The "click" event binding responds by calling `DashboardHeroComponent.click()`.
|
The "click" event binding responds by calling `DashboardHeroComponent.click()`.
|
||||||
|
|
||||||
`heroEl`是个`DebugElement`,它代表了英雄所在的`<div>`。
|
`heroEl`是个`DebugElement`,它代表了英雄所在的`<div>`。
|
||||||
测试程序用"click"事件名字来调用`triggerEventHandler`。
|
测试程序用"click"事件名字来调用`triggerEventHandler`。
|
||||||
调用`DashboardHeroComponent.click()`时,"click"事件绑定作出响应。
|
调用`DashboardHeroComponent.click()`时,"click"事件绑定作出响应。
|
||||||
|
|
||||||
If the component behaves as expected, `click()` tells the component's `selected` property to emit the `hero` object,
|
If the component behaves as expected, `click()` tells the component's `selected` property to emit the `hero` object,
|
||||||
the test detects that value through its subscription to `selected`, and the test should pass.
|
the test detects that value through its subscription to `selected`, and the test should pass.
|
||||||
如果组件想期待的那样工作,`click()`通知组件的`selected`属性发出`hero`对象,测试程序通过订阅`selected`事件而检测到这个值,所以测试应该成功。
|
|
||||||
|
如果组件像期待的那样工作,`click()`通知组件的`selected`属性就会发出`hero`对象,测试程序通过订阅`selected`事件而检测到这个值,所以测试应该成功。
|
||||||
|
|
||||||
a#trigger-event-handler
|
a#trigger-event-handler
|
||||||
:marked
|
:marked
|
||||||
### _triggerEventHandler_
|
### _triggerEventHandler_
|
||||||
@ -1484,6 +1522,7 @@ a#click-helper
|
|||||||
|
|
||||||
点击按钮、链接或者任意HTML元素是很常见的测试任务。
|
点击按钮、链接或者任意HTML元素是很常见的测试任务。
|
||||||
把**click触发**过程封装到辅助方法中可以简化这个任务,比如下面的`click`辅助方法:
|
把**click触发**过程封装到辅助方法中可以简化这个任务,比如下面的`click`辅助方法:
|
||||||
|
|
||||||
+makeExample('testing/ts/src/testing/index.ts', 'click-event', 'testing/index.ts (click helper)')(format='.')
|
+makeExample('testing/ts/src/testing/index.ts', 'click-event', 'testing/index.ts (click helper)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
@ -1618,6 +1657,7 @@ a#routed-component
|
|||||||
Fortunately, the `DashboardComponent` isn't doing much with the `Router`
|
Fortunately, the `DashboardComponent` isn't doing much with the `Router`
|
||||||
|
|
||||||
幸运的是,`DashbaordComponent`没有使用`Router`做很多事情。
|
幸运的是,`DashbaordComponent`没有使用`Router`做很多事情。
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/dashboard/dashboard.component.ts', 'goto-detail', 'src/app/dashboard/dashboard.component.ts (goToDetail)')(format='.')
|
+makeExample('testing/ts/src/app/dashboard/dashboard.component.ts', 'goto-detail', 'src/app/dashboard/dashboard.component.ts (goToDetail)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
@ -1628,17 +1668,22 @@ a#routed-component
|
|||||||
|
|
||||||
通常都是这样的。原则上,你测试的是组件,不是路由器,应该只关心在指定的条件下,组件是否导航到正确的地址。
|
通常都是这样的。原则上,你测试的是组件,不是路由器,应该只关心在指定的条件下,组件是否导航到正确的地址。
|
||||||
用模拟类来替换路由器是一种简单的方案。下面的代码应该可以:
|
用模拟类来替换路由器是一种简单的方案。下面的代码应该可以:
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/dashboard/dashboard.component.spec.ts', 'router-stub', 'src/app/dashboard/dashboard.component.spec.ts (Router Stub)')(format='.')
|
+makeExample('testing/ts/src/app/dashboard/dashboard.component.spec.ts', 'router-stub', 'src/app/dashboard/dashboard.component.spec.ts (Router Stub)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Now set up the testing module with the test stubs for the `Router` and `HeroService`, and
|
Now set up the testing module with the test stubs for the `Router` and `HeroService`, and
|
||||||
create a test instance of the `DashboardComponent` for subsequent testing.
|
create a test instance of the `DashboardComponent` for subsequent testing.
|
||||||
|
|
||||||
现在我们来利用`Router`和`HeroService`的测试stub类来配置测试模块,并为接下来的测试创建`DashboardComponent`的测试实例。
|
现在我们来利用`Router`和`HeroService`的测试stub类来配置测试模块,并为接下来的测试创建`DashboardComponent`的测试实例。
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/dashboard/dashboard.component.spec.ts', 'compile-and-create-body', 'src/app/dashboard/dashboard.component.spec.ts (compile and create)')(format='.')
|
+makeExample('testing/ts/src/app/dashboard/dashboard.component.spec.ts', 'compile-and-create-body', 'src/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是所期待的值。
|
下面的测试程序点击显示的英雄,并利用spy来确认`Router.navigateByUrl`被调用了,而且传进的url是所期待的值。
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/dashboard/dashboard.component.spec.ts', 'navigate-test', 'src/app/dashboard/dashboard.component.spec.ts (navigate test)')(format='.')
|
+makeExample('testing/ts/src/app/dashboard/dashboard.component.spec.ts', 'navigate-test', 'src/app/dashboard/dashboard.component.spec.ts (navigate test)')(format='.')
|
||||||
|
|
||||||
|
|
||||||
@ -1651,7 +1696,9 @@ a#inject
|
|||||||
Notice the `inject` function in the second `it` argument.
|
Notice the `inject` function in the second `it` argument.
|
||||||
|
|
||||||
注意第二个`it`参数里面的`inject`函数。
|
注意第二个`it`参数里面的`inject`函数。
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/dashboard/dashboard.component.spec.ts', 'inject')(format='.')
|
+makeExample('testing/ts/src/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.
|
||||||
@ -1673,7 +1720,9 @@ a#inject
|
|||||||
|
|
||||||
.callout.is-important
|
.callout.is-important
|
||||||
header inject uses the TestBed Injector
|
header inject uses the TestBed Injector
|
||||||
|
|
||||||
header 使用TestBed注入器来注入
|
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.
|
||||||
@ -1895,12 +1944,14 @@ a#page-object
|
|||||||
|
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/testing/hero-detail.component.png' alt="HeroDetailComponent in action")
|
img(src='/resources/images/devguide/testing/hero-detail.component.png' alt="HeroDetailComponent in action")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
But there's already plenty of template complexity.
|
But there's already plenty of template complexity.
|
||||||
|
|
||||||
但是它已经有很多模板复杂性。
|
但是它已经有很多模板复杂性。
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/hero/hero-detail.component.html', '', 'src/app/hero/hero-detail.component.html')(format='.')
|
+makeExample('testing/ts/src/app/hero/hero-detail.component.html', '', 'src/app/hero/hero-detail.component.html')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
To fully exercise the component, the test needs a lot of setup:
|
To fully exercise the component, the test needs a lot of setup:
|
||||||
|
|
||||||
@ -2014,6 +2065,7 @@ a#import-module
|
|||||||
One approach is to configure the testing module from the individual pieces as in this example:
|
One approach is to configure the testing module from the individual pieces as in this example:
|
||||||
|
|
||||||
一种方法是在测试模块中一一配置,就像这样:
|
一种方法是在测试模块中一一配置,就像这样:
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/hero/hero-detail.component.spec.ts', 'setup-forms-module', 'src/app/hero/hero-detail.component.spec.ts (FormsModule setup)')(format='.')
|
+makeExample('testing/ts/src/app/hero/hero-detail.component.spec.ts', 'setup-forms-module', 'src/app/hero/hero-detail.component.spec.ts (FormsModule setup)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
@ -2043,6 +2095,7 @@ a#feature-module-import
|
|||||||
|
|
||||||
`HeroDetailComponent`是`HeroModule`[特征模块](ngmodule.html#feature-modules)的一部分,它组合了更多互相依赖的部件,包括`SharedModule`。
|
`HeroDetailComponent`是`HeroModule`[特征模块](ngmodule.html#feature-modules)的一部分,它组合了更多互相依赖的部件,包括`SharedModule`。
|
||||||
试试下面这个导入`HeroModule`的测试配置:
|
试试下面这个导入`HeroModule`的测试配置:
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/hero/hero-detail.component.spec.ts', 'setup-hero-module', 'src/app/hero/hero-detail.component.spec.ts (HeroModule setup)')(format='.')
|
+makeExample('testing/ts/src/app/hero/hero-detail.component.spec.ts', 'setup-hero-module', 'src/app/hero/hero-detail.component.spec.ts (HeroModule setup)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
@ -2287,12 +2340,17 @@ a#stub-component
|
|||||||
|
|
||||||
* The real `RouterOutlet` is complex and errors easily.
|
* The real `RouterOutlet` is complex and errors easily.
|
||||||
The `RouterOutletStubComponent` (in `testing/router-stubs.ts`) is safely inert.
|
The `RouterOutletStubComponent` (in `testing/router-stubs.ts`) is safely inert.
|
||||||
|
|
||||||
真实的`RouterOutlet`很复杂而且容易出错。
|
真实的`RouterOutlet`很复杂而且容易出错。
|
||||||
`testing/router-stubs.ts`里的`RouterOutletStubComponent`是安全的替代品。
|
`testing/router-stubs.ts`里的`RouterOutletStubComponent`是安全的替代品。
|
||||||
|
|
||||||
The component stubs are essential.
|
The component stubs are essential.
|
||||||
Without them, the Angular compiler doesn't recognize the `<app-welcome>` and `<router-outlet>` tags
|
Without them, the Angular compiler doesn't recognize the `<app-welcome>` and `<router-outlet>` tags
|
||||||
and throws an error. 组件stub替代品很关键。
|
and throws an error.
|
||||||
|
|
||||||
|
组件stub替代品很关键。
|
||||||
没有它们,Angular编译器无法识别`<app-welcome`和`<router-outlet>`标签,抛出错误。
|
没有它们,Angular编译器无法识别`<app-welcome`和`<router-outlet>`标签,抛出错误。
|
||||||
|
|
||||||
a#router-link-stub
|
a#router-link-stub
|
||||||
:marked
|
:marked
|
||||||
### Stubbing the _RouterLink_
|
### Stubbing the _RouterLink_
|
||||||
@ -2353,9 +2411,11 @@ a#app-component-tests
|
|||||||
It works hard to appear useful when in fact it
|
It works hard to appear useful when in fact it
|
||||||
tests the `RouterLinkStubDirective` rather than the _component_.
|
tests the `RouterLinkStubDirective` rather than the _component_.
|
||||||
This is a common failing of directive stubs.
|
This is a common failing of directive stubs.
|
||||||
|
|
||||||
本例中的“click”测试程序其实毫无价值。
|
本例中的“click”测试程序其实毫无价值。
|
||||||
它显得很有用,但是事实上,它测试的是`RouterLinkStubDirective`,而非测试组件。
|
它显得很有用,但是事实上,它测试的是`RouterLinkStubDirective`,而非测试组件。
|
||||||
这是指令stub的通病。
|
这是指令stub的通病。
|
||||||
|
|
||||||
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.
|
||||||
@ -2393,9 +2453,15 @@ a#why-stubbed-routerlink-tests
|
|||||||
|
|
||||||
A _different_ battery of tests can explore whether the application navigates as expected
|
A _different_ battery of tests can explore whether the application navigates as expected
|
||||||
in the presence of conditions that influence guards such as whether the user is authenticated and authorized.
|
in the presence of conditions that influence guards such as whether the user is authenticated and authorized.
|
||||||
|
|
||||||
|
不同的测试程序可以探索在不同条件下(比如像检查用户是否认证),该应用是否和期望的那样导航。
|
||||||
|
|
||||||
.alert.is-helpful
|
.alert.is-helpful
|
||||||
:marked A future guide update will explain how to write such tests with the `RouterTestingModule`.不同的测试程序可以探索在不同条件下(比如像检查用户是否认证),该应用是否和期望的那样导航。
|
:marked
|
||||||
|
A future guide update will explain how to write such tests with the `RouterTestingModule`.
|
||||||
|
|
||||||
未来本章的更新将介绍如何使用`RouterTestingModule`来编写这样的测试程序。
|
未来本章的更新将介绍如何使用`RouterTestingModule`来编写这样的测试程序。
|
||||||
|
|
||||||
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 回到顶部
|
||||||
.l-hr
|
.l-hr
|
||||||
@ -2408,7 +2474,9 @@ a#shallow-component-test
|
|||||||
|
|
||||||
The [previous setup](#stub-component) declared the `BannerComponent` and stubbed two other components
|
The [previous setup](#stub-component) declared the `BannerComponent` and stubbed two other components
|
||||||
for _no reason other than to avoid a compiler error_.
|
for _no reason other than to avoid a compiler error_.
|
||||||
|
|
||||||
[以前的配置](#stub-component)声明了`BannerComponent`,并stub伪造了两个其它组件,**仅仅是为了避免编译错误,不是为别的原因**。
|
[以前的配置](#stub-component)声明了`BannerComponent`,并stub伪造了两个其它组件,**仅仅是为了避免编译错误,不是为别的原因**。
|
||||||
|
|
||||||
Without them, the Angular compiler doesn't recognize the `<app-banner>`, `<app-welcome>` and `<router-outlet>` tags
|
Without them, the Angular compiler doesn't recognize the `<app-banner>`, `<app-welcome>` and `<router-outlet>` tags
|
||||||
in the [_app.component.html_](#app-component-html) template and throws an error.
|
in the [_app.component.html_](#app-component-html) template and throws an error.
|
||||||
|
|
||||||
@ -2417,17 +2485,20 @@ a#shallow-component-test
|
|||||||
Add `NO_ERRORS_SCHEMA` to the testing module's `schemas` metadata
|
Add `NO_ERRORS_SCHEMA` to the testing module's `schemas` metadata
|
||||||
to tell the compiler to ignore unrecognized elements and attributes.
|
to tell the compiler to ignore unrecognized elements and attributes.
|
||||||
You no longer have to declare irrelevant components and directives.
|
You no longer have to declare irrelevant components and directives.
|
||||||
|
|
||||||
添加`NO_ERRORS_SCHEMA`到测试模块的`schemas`元数据中,告诉编译器忽略不认识的元素和属性。
|
添加`NO_ERRORS_SCHEMA`到测试模块的`schemas`元数据中,告诉编译器忽略不认识的元素和属性。
|
||||||
这样你不再需要声明无关组件和指令。
|
这样你不再需要声明无关组件和指令。
|
||||||
These tests are ***shallow*** because they only "go deep" into the components you want to test.
|
|
||||||
|
|
||||||
|
These tests are ***shallow*** because they only "go deep" into the components you want to test.
|
||||||
Here is a setup, with `import` statements, that demonstrates the improved simplicity of _shallow_ tests, relative to the stubbing setup.
|
Here is a setup, with `import` statements, that demonstrates the improved simplicity of _shallow_ tests, relative to the stubbing setup.
|
||||||
|
|
||||||
这些测试程序比较**浅**,因为它们只“深入”到你要测试的组件。
|
这些测试程序比较**浅**,因为它们只“深入”到你要测试的组件。
|
||||||
这里是一套配置(拥有`import`语句),体现了相比使用stub伪造的配置来说,**浅**测试程序的简单性。
|
这里是一套配置(拥有`import`语句),体现了相比使用stub伪造的配置来说,**浅**测试程序的简单性。
|
||||||
|
|
||||||
+makeTabs('testing/ts/src/app/app.component.spec.ts, testing/ts/src/app/app.component.spec.ts',
|
+makeTabs('testing/ts/src/app/app.component.spec.ts, testing/ts/src/app/app.component.spec.ts',
|
||||||
'setup-schemas, setup-stubs-w-imports',
|
'setup-schemas, setup-stubs-w-imports',
|
||||||
'src/app/app.component.spec.ts (NO_ERRORS_SCHEMA), src/app/app.component.spec.ts (Stubs)')(format='.')
|
'src/app/app.component.spec.ts (NO_ERRORS_SCHEMA), src/app/app.component.spec.ts (Stubs)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The _only_ declarations are the _component-under-test_ (`AppComponent`) and the `RouterLinkStubDirective`
|
The _only_ declarations are the _component-under-test_ (`AppComponent`) and the `RouterLinkStubDirective`
|
||||||
that contributes actively to the tests.
|
that contributes actively to the tests.
|
||||||
@ -2485,7 +2556,9 @@ a#attribute-directive
|
|||||||
Finding and testing all components that use the directive is tedious, brittle, and almost as unlikely to afford full coverage.
|
Finding and testing all components that use the directive is tedious, brittle, and almost as unlikely to afford full coverage.
|
||||||
|
|
||||||
但是,测试单一的用例一般无法探索该指令的全部能力。
|
但是,测试单一的用例一般无法探索该指令的全部能力。
|
||||||
查找和测试所有使用该指令的组件非常繁琐和脆弱,并且通常无法覆盖所有组件。[Isolated unit tests](#isolated-unit-tests) might be helpful,
|
查找和测试所有使用该指令的组件非常繁琐和脆弱,并且通常无法覆盖所有组件。
|
||||||
|
|
||||||
|
[Isolated unit tests](#isolated-unit-tests) might be helpful,
|
||||||
but attribute directives like this one tend to manipulate the DOM.
|
but attribute directives like this one tend to manipulate the DOM.
|
||||||
Isolated unit tests don't touch the DOMand, therefore ,
|
Isolated unit tests don't touch the DOMand, therefore ,
|
||||||
do not inspire confidence in the directive's efficacy.
|
do not inspire confidence in the directive's efficacy.
|
||||||
@ -2690,7 +2763,9 @@ a#services-with-dependencies
|
|||||||
+makeExample('testing/ts/src/app/bag/bag.no-testbed.spec.ts', 'DependentService', 'src/app/bag/bag.no-testbed.spec.ts')
|
+makeExample('testing/ts/src/app/bag/bag.no-testbed.spec.ts', 'DependentService', 'src/app/bag/bag.no-testbed.spec.ts')
|
||||||
:marked
|
:marked
|
||||||
The first test creates a `FancyService` with `new` and passes it to the `DependentService` constructor.
|
The first test creates a `FancyService` with `new` and passes it to the `DependentService` constructor.
|
||||||
|
|
||||||
第一个测试程序使用`new`创建`FancyService`实例,并将它传递给`DependentService`构造函数。
|
第一个测试程序使用`new`创建`FancyService`实例,并将它传递给`DependentService`构造函数。
|
||||||
|
|
||||||
However, it's rarely that simple. The injected service can be difficult to create or control.
|
However, it's rarely that simple. The injected service can be difficult to create or control.
|
||||||
You can mock the dependency, use a dummy value, or stub the pertinent service method
|
You can mock the dependency, use a dummy value, or stub the pertinent service method
|
||||||
with a substitute method that 's easy to control.
|
with a substitute method that 's easy to control.
|
||||||
@ -2720,15 +2795,19 @@ a#isolated-pipe-tests
|
|||||||
The `transform` implementation rarely interacts with the DOM.
|
The `transform` implementation rarely interacts with the DOM.
|
||||||
Most pipes have no dependence on Angular other than the `@Pipe`
|
Most pipes have no dependence on Angular other than the `@Pipe`
|
||||||
metadata and an interface.
|
metadata and an interface.
|
||||||
|
|
||||||
管道类有一个方法,`transform`,用来转换输入值到输出值。
|
管道类有一个方法,`transform`,用来转换输入值到输出值。
|
||||||
`transform`的实现很少与DOM交互。
|
`transform`的实现很少与DOM交互。
|
||||||
除了`@Pipe`元数据和一个接口外,大部分管道不依赖Angular。
|
除了`@Pipe`元数据和一个接口外,大部分管道不依赖Angular。
|
||||||
|
|
||||||
Consider a `TitleCasePipe` that capitalizes the first letter of each word.
|
Consider a `TitleCasePipe` that capitalizes the first letter of each word.
|
||||||
Here's a naive implementation with a regular expression.
|
Here's a naive implementation with a regular expression.
|
||||||
|
|
||||||
假设`TitleCasePipe`将每个单词的第一个字母变成大写。
|
假设`TitleCasePipe`将每个单词的第一个字母变成大写。
|
||||||
下面是使用正则表达式实现的简单代码:
|
下面是使用正则表达式实现的简单代码:
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/shared/title-case.pipe.ts', '', 'src/app/shared/title-case.pipe.ts')(format='.')
|
+makeExample('testing/ts/src/app/shared/title-case.pipe.ts', '', 'src/app/shared/title-case.pipe.ts')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Anything that uses a regular expression is worth testing thoroughly.
|
Anything that uses a regular expression is worth testing thoroughly.
|
||||||
Use simple Jasmine to explore the expected cases and the edge cases.
|
Use simple Jasmine to explore the expected cases and the edge cases.
|
||||||
@ -2743,6 +2822,7 @@ a#write-tests
|
|||||||
### Write Angular tests too
|
### Write Angular tests too
|
||||||
|
|
||||||
#### 同时也编写Angular测试
|
#### 同时也编写Angular测试
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
@ -2752,6 +2832,7 @@ a#write-tests
|
|||||||
Consider adding component tests such as this one:
|
Consider adding component tests such as this one:
|
||||||
|
|
||||||
考虑像这样添加组件测试程序:
|
考虑像这样添加组件测试程序:
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/hero/hero-detail.component.spec.ts', 'title-case-pipe', 'src/app/hero/hero-detail.component.spec.ts (pipe test)')
|
+makeExample('testing/ts/src/app/hero/hero-detail.component.spec.ts', 'title-case-pipe', 'src/app/hero/hero-detail.component.spec.ts (pipe test)')
|
||||||
|
|
||||||
a#isolated-component-tests
|
a#isolated-component-tests
|
||||||
@ -2769,12 +2850,15 @@ a#isolated-component-tests
|
|||||||
Consider this `ButtonComp` component.
|
Consider this `ButtonComp` component.
|
||||||
|
|
||||||
考虑这个`ButtonComp`组件。
|
考虑这个`ButtonComp`组件。
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/bag/bag.ts', 'ButtonComp', 'src/app/bag/bag.ts (ButtonComp)')(format='.')
|
+makeExample('testing/ts/src/app/bag/bag.ts', 'ButtonComp', 'src/app/bag/bag.ts (ButtonComp)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The following Angular test demonstrates that clicking a button in the template leads
|
The following Angular test demonstrates that clicking a button in the template leads
|
||||||
to an update of the on-screen message.
|
to an update of the on-screen message.
|
||||||
|
|
||||||
下面的Angular测试演示点击模板里的按钮后,引起了屏幕上的消息的更新。
|
下面的Angular测试演示点击模板里的按钮后,引起了屏幕上的消息的更新。
|
||||||
|
|
||||||
+makeExample('testing/ts/src/app/bag/bag.spec.ts', 'ButtonComp', 'src/app/bag/bag.spec.ts (ButtonComp)')(format='.')
|
+makeExample('testing/ts/src/app/bag/bag.spec.ts', 'ButtonComp', 'src/app/bag/bag.spec.ts (ButtonComp)')(format='.')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
@ -2903,8 +2987,10 @@ table
|
|||||||
:marked
|
:marked
|
||||||
When a `fakeAsync` test ends with pending timer event _tasks_ (queued `setTimeOut` and `setInterval` callbacks),
|
When a `fakeAsync` test ends with pending timer event _tasks_ (queued `setTimeOut` and `setInterval` callbacks),
|
||||||
the test fails with a clear error message.
|
the test fails with a clear error message.
|
||||||
|
|
||||||
当`fakeAsync`测试程序以正在运行的计时器事件**任务**(排队中的`setTimeOut`和`setInterval`的回调)结束时,
|
当`fakeAsync`测试程序以正在运行的计时器事件**任务**(排队中的`setTimeOut`和`setInterval`的回调)结束时,
|
||||||
测试会失败,并显示一条明确的错误信息。
|
测试会失败,并显示一条明确的错误信息。
|
||||||
|
|
||||||
In general, a test should end with no queued tasks.
|
In general, a test should end with no queued tasks.
|
||||||
When pending timer tasks are expected, call `discardPeriodicTasks` to flush the _task_ queue
|
When pending timer tasks are expected, call `discardPeriodicTasks` to flush the _task_ queue
|
||||||
and avoid the error.
|
and avoid the error.
|
||||||
@ -2918,7 +3004,9 @@ table
|
|||||||
:marked
|
:marked
|
||||||
When a `fakeAsync` test ends with pending _micro-tasks_ such as unresolved promises,
|
When a `fakeAsync` test ends with pending _micro-tasks_ such as unresolved promises,
|
||||||
the test fails with a clear error message.
|
the test fails with a clear error message.
|
||||||
|
|
||||||
当`fakeAsync`测试程序以待执行**微任务**(比如未解析的承诺)结束时,测试会失败并显示明确的错误信息。
|
当`fakeAsync`测试程序以待执行**微任务**(比如未解析的承诺)结束时,测试会失败并显示明确的错误信息。
|
||||||
|
|
||||||
In general, a test should wait for micro-tasks to finish.
|
In general, a test should wait for micro-tasks to finish.
|
||||||
When pending microtasks are expected, call `flushMicrotasks` to flush the _micro-task_ queue
|
When pending microtasks are expected, call `flushMicrotasks` to flush the _micro-task_ queue
|
||||||
and avoid the error.
|
and avoid the error.
|
||||||
@ -2993,7 +3081,9 @@ code-example(format="." language="javascript").
|
|||||||
a#testbed-methods
|
a#testbed-methods
|
||||||
:marked
|
:marked
|
||||||
The `TestBed` API consists of static class methods that either update or reference a _global_ instance of the`TestBed`.
|
The `TestBed` API consists of static class methods that either update or reference a _global_ instance of the`TestBed`.
|
||||||
|
|
||||||
`TestBed`的API包含了一系列静态类方法,它们更新或者引用**全局**的`TestBed`实例。
|
`TestBed`的API包含了一系列静态类方法,它们更新或者引用**全局**的`TestBed`实例。
|
||||||
|
|
||||||
Internally, all static methods cover methods of the current runtime `TestBed` instance ,
|
Internally, all static methods cover methods of the current runtime `TestBed` instance ,
|
||||||
which is also returned by the `getTestBed()` function.
|
which is also returned by the `getTestBed()` function.
|
||||||
|
|
||||||
@ -3006,6 +3096,7 @@ a#testbed-methods
|
|||||||
Here are the most important static methods, in order of likely utility.
|
Here are the most important static methods, in order of likely utility.
|
||||||
|
|
||||||
这里列出了最重要的静态方法,以使用频率排序:
|
这里列出了最重要的静态方法,以使用频率排序:
|
||||||
|
|
||||||
table
|
table
|
||||||
tr
|
tr
|
||||||
th
|
th
|
||||||
@ -3021,12 +3112,15 @@ table
|
|||||||
The testing shims (`karma-test-shim`, `browser-test-shim`)
|
The testing shims (`karma-test-shim`, `browser-test-shim`)
|
||||||
establish the [initial test environment](##testbed-initTestEnvironment) and a default testing module.
|
establish the [initial test environment](##testbed-initTestEnvironment) and a default testing module.
|
||||||
The default testing module is configured with basic declaratives and some Angular service substitutes that every tester needs.
|
The default testing module is configured with basic declaratives and some Angular service substitutes that every tester needs.
|
||||||
|
|
||||||
测试垫片(`karma-test-shim`, `browser-test-shim`)创建了[初始测试环境](##testbed-initTestEnvironment)和默认测试模块。
|
测试垫片(`karma-test-shim`, `browser-test-shim`)创建了[初始测试环境](##testbed-initTestEnvironment)和默认测试模块。
|
||||||
默认测试模块是使用基本声明和一些Angular服务替代品,它们是所有测试程序都需要的。
|
默认测试模块是使用基本声明和一些Angular服务替代品,它们是所有测试程序都需要的。
|
||||||
|
|
||||||
Call `configureTestingModule` to refine the testing module configuration for a particular set of tests
|
Call `configureTestingModule` to refine the testing module configuration for a particular set of tests
|
||||||
by adding and removing imports, declarations (of components, directives, and pipes), and providers.
|
by adding and removing imports, declarations (of components, directives, and pipes), and providers.
|
||||||
|
|
||||||
调用`configureTestingModule`来为一套特定的测试定义测试模块配置,添加和删除导入、(组件、指令和管道的)声明和服务提供商。
|
调用`configureTestingModule`来为一套特定的测试定义测试模块配置,添加和删除导入、(组件、指令和管道的)声明和服务提供商。
|
||||||
|
|
||||||
tr
|
tr
|
||||||
td(style="vertical-align: top") <code>compileComponents</code>
|
td(style="vertical-align: top") <code>compileComponents</code>
|
||||||
td
|
td
|
||||||
@ -3181,7 +3275,9 @@ a#component-fixture-properties
|
|||||||
#### _ComponentFixture_的属性
|
#### _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.
|
||||||
|
|
||||||
下面是对测试最重要的属性,以使用频率排序:
|
下面是对测试最重要的属性,以使用频率排序:
|
||||||
|
|
||||||
table
|
table
|
||||||
tr
|
tr
|
||||||
th
|
th
|
||||||
@ -3398,7 +3494,9 @@ table
|
|||||||
td
|
td
|
||||||
:marked
|
:marked
|
||||||
The element's own component instance, if it has one.
|
The element's own component instance, if it has one.
|
||||||
元素自己的组件实例(如果有)。 tr
|
|
||||||
|
元素自己的组件实例(如果有)。
|
||||||
|
tr
|
||||||
td(style="vertical-align: top") <code>context</code>
|
td(style="vertical-align: top") <code>context</code>
|
||||||
td
|
td
|
||||||
:marked
|
:marked
|
||||||
|
@ -406,20 +406,27 @@ a(id="common-configuration")
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
### Common configuration
|
### Common configuration
|
||||||
|
|
||||||
### 通用配置
|
### 通用配置
|
||||||
|
|
||||||
Developers typically have separate configurations for development, production, and test environments.
|
Developers typically have separate configurations for development, production, and test environments.
|
||||||
All three have a lot of configuration in common.
|
All three have a lot of configuration in common.
|
||||||
|
|
||||||
开发、生产、测试等不同的环境通常会分开配置,但实际上这些配置也有很多地方是通用的。
|
开发、生产、测试等不同的环境通常会分开配置,但实际上这些配置也有很多地方是通用的。
|
||||||
|
|
||||||
Gather the common configuration in a file called `webpack.common.js`.
|
Gather the common configuration in a file called `webpack.common.js`.
|
||||||
|
|
||||||
我们可以把这些通用的配置收归到一个文件,命名为`webpack.common.js`。
|
我们可以把这些通用的配置收归到一个文件,命名为`webpack.common.js`。
|
||||||
|
|
||||||
+makeExample('webpack/ts/config/webpack.common.js', null, 'config/webpack.common.js')(format=".")
|
+makeExample('webpack/ts/config/webpack.common.js', null, 'config/webpack.common.js')(format=".")
|
||||||
|
|
||||||
a#inside-webpack-commonjs
|
a#inside-webpack-commonjs
|
||||||
:marked
|
:marked
|
||||||
### Inside _webpack.common.js_
|
### Inside _webpack.common.js_
|
||||||
### webpack.common.js解读 Webpack is a NodeJS-based tool that reads configuration from a JavaScript commonjs module file.
|
|
||||||
|
### webpack.common.js解读
|
||||||
|
|
||||||
|
Webpack is a NodeJS-based tool that reads configuration from a JavaScript commonjs module file.
|
||||||
|
|
||||||
Webpack是基于NodeJS的一个工具,它能够从一个*commonjs*规范的JavaScript模块文件里读取配置。
|
Webpack是基于NodeJS的一个工具,它能够从一个*commonjs*规范的JavaScript模块文件里读取配置。
|
||||||
|
|
||||||
@ -449,7 +456,9 @@ a#common-entries
|
|||||||
#### _entry_
|
#### _entry_
|
||||||
|
|
||||||
The first export is the `entry` object:
|
The first export is the `entry` object:
|
||||||
|
|
||||||
如上所述,第一个导出的对象是*entries*:
|
如上所述,第一个导出的对象是*entries*:
|
||||||
|
|
||||||
+makeExample('webpack/ts/config/webpack.common.js', 'entries', 'config/webpack.common.js')(format=".")
|
+makeExample('webpack/ts/config/webpack.common.js', 'entries', 'config/webpack.common.js')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
|
Loading…
x
Reference in New Issue
Block a user