# 测试实用工具 API
本页面描述了一些最有用的 Angular 测试特性。
Angular 测试实用工具包括 TestBed
、ComponentFixture
以及一些控制测试环境的函数。TestBed和 ComponentFixture
类是单独介绍的。
下面是一些独立函数的摘要,以使用频率排序:
函数 | Function | 详情 | Details |
---|---|---|---|
waitForAsync | 在一个特殊的async 测试区域中运行测试(it)的函数体或准备函数(beforeEach)。参阅 waitForAsync。Runs the body of a test (it) or setup (beforeEach) function within a special async test zone. See waitForAsync. | ||
fakeAsync | 在一个特殊的fakeAsync 测试区域中运行测试(it)的函数体,以便启用线性风格的控制流。参阅 fakeAsync。Runs the body of a test (it) within a special fakeAsync test zone, enabling a linear control flow coding style. See fakeAsync. | ||
tick | 通过在 fakeAsync 测试区域中刷新定时器和微任务(micro-task)队列来仿真时间的流逝以及异步活动的完成。 好奇和执着的读者可能会喜欢这篇长博客:" 任务、微任务、队列和调度器 ". 接受一个可选参数,它可以把虚拟时钟往前推进特定的微秒数。清除调度到那个时间帧中的异步活动。参阅 tick。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. The curious, dedicated reader might enjoy this lengthy blog post, "Tasks, microtasks, queues and schedules". Accepts an optional argument that moves the virtual clock forward by the specified number of milliseconds, clearing asynchronous activities scheduled within that timeframe. See tick. | ||
inject | 从当前的 TestBed 注入器中把一个或多个服务注入到一个测试函数中。它不能用于注入组件自身提供的服务。参阅 debugElement.injector 部分的讨论。Injects one or more services from the current TestBed injector into a test function. It cannot inject a service provided by the component itself. See discussion of the debugElement.injector. | ||
discardPeriodicTasks | 当 fakeAsync 测试程序以正在运行的计时器事件任务(排队中的 setTimeOut 和 setInterval 的回调)结束时,测试会失败,并显示一条明确的错误信息。 一般来讲,测试程序应该以无排队任务结束。当待执行计时器任务存在时,调用 discardPeriodicTasks 来触发任务队列,防止该错误发生。When a fakeAsync() test ends with pending timer event tasks (queued setTimeOut and setInterval callbacks), the test fails with a clear error message. In general, a test should end with no queued tasks. When pending timer tasks are expected, call discardPeriodicTasks to flush the task queue and avoid the error. | ||
flushMicrotasks | 当 fakeAsync 测试程序以待执行微任务(比如未解析的 Promise )结束时,测试会失败并显示明确的错误信息。 一般来说,测试应该等待微任务结束。当待执行微任务存在时,调用 flushMicrotasks 来触发微任务队列,防止该错误发生。When a fakeAsync() test ends with pending micro-tasks such as unresolved promises, the test fails with a clear error message. In general, a test should wait for micro-tasks to finish. When pending microtasks are expected, call flushMicrotasks to flush the micro-task queue and avoid the error. | ||
ComponentFixtureAutoDetect | 一个服务提供者令牌,用于开启自动变更检测。A provider token for a service that turns on automatic change detection. | ||
getTestBed | 获取当前 TestBed 实例。通常用不上,因为 TestBed 的静态类方法已经够用。TestBed 实例有一些很少需要用到的方法,它们没有对应的静态方法。Gets the current instance of the TestBed. Usually unnecessary because the static class methods of the TestBed class are typically sufficient. The TestBed instance exposes a few rarely used members that are not available as static methods. |
# TestBed
类摘要
# TestBed
类是 Angular 测试工具的主要类之一。它的 API 很庞大,可能有点过于复杂,直到你一点一点的探索它们。阅读本章前面的部分,了解了基本的知识以后,再试着了解完整 API。
传给 configureTestingModule
的模块定义是 @NgModule
元数据属性的子集。
type TestModuleMetadata = {
providers?: any[];
declarations?: any[];
imports?: any[];
schemas?: Array<SchemaMetadata | any[]>;
};
每一个重载方法接受一个 MetadataOverride<T>
,这里 T
是适合这个方法的元数据类型,也就是 @NgModule
、@Component
、@Directive
或者 @Pipe
的参数。
type MetadataOverride<T> = {
add?: Partial<T>;
remove?: Partial<T>;
set?: Partial<T>;
};
TestBed
的 API 包含了一系列静态类方法,它们更新或者引用全局的 TestBed
实例。
在内部,所有静态方法在 getTestBed()
函数返回的当前运行时间的 TestBed
实例上都有对应的方法。
在 BeforeEach()
内调用 TestBed
方法,以确保在运行每个单独测试时,都有崭新的开始。
这里列出了最重要的静态方法,以使用频率排序。
少数 TestBed
实例方法没有对应的静态方法。它们很少被使用。
# ComponentFixture
类
# TestBed.createComponent<T>
会创建一个组件 T
的实例,并为该组件返回一个强类型的 ComponentFixture
。
ComponentFixture
的属性和方法提供了对组件、它的 DOM 和它的 Angular 环境方面的访问。
# ComponentFixture
的属性
# 下面是对测试最重要的属性,以使用频率排序。
属性 | Properties | 详情 | Details |
---|---|---|---|
componentInstance | 被 TestBed.createComponent 创建的组件类实例。The instance of the component class created by TestBed.createComponent. | ||
debugElement | 与组件根元素关联的 DebugElement。 debugElement 提供了在测试和调试期间深入探查组件及其 DOM 元素的功能。它对于测试者是一个极其重要的属性。它的大多数主要成员在后面都有讲解。The DebugElement associated with the root element of the component. 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. | ||
nativeElement | 组件的原生根 DOM 元素。The native DOM element at the root of the component. | ||
changeDetectorRef | 组件的 ChangeDetectorRef。 在测试一个拥有 ChangeDetectionStrategy.OnPush 的组件,或者在组件的变化测试在你的程序控制下时,ChangeDetectorRef 是最重要的。The ChangeDetectorRef for the component. The ChangeDetectorRef is most valuable when testing a component that has the ChangeDetectionStrategy.OnPush method or the component's change detection is under your programmatic control. |
# ComponentFixture
方法
# fixture方法使 Angular 对组件树执行某些任务。在触发 Angular 行为来模拟的用户行为时,调用这些方法。
下面是对测试最有用的方法。
方法 | Methods | 详情 | Details |
---|---|---|---|
detectChanges | 为组件触发一轮变化检查。 调用它来初始化组件(它调用 ngOnInit)。或者在你的测试代码改变了组件的数据绑定属性值后调用它。Angular 不能检测到你已经改变了 personComponent.name 属性,也不会更新 name 的绑定,直到你调用了 detectChanges。 之后,运行 checkNoChanges,来确认没有循环更新,除非它被这样调用:detectChanges(false)。Trigger a change detection cycle for the component. Call it to initialize the component (it calls ngOnInit) and after your test code, change the component's data bound property values. Angular can't see that you've changed personComponent.name and won't update the name binding until you call detectChanges. Runs checkNoChanges afterwards to confirm that there are no circular updates unless called as detectChanges(false); | ||
autoDetectChanges | 如果你希望这个夹具自动检测变更,就把这个设置为 true。 当自动检测打开时,测试 fixture 监听 zone 事件,并调用 detectChanges。当你的测试代码直接修改了组件属性值时,你还是要调用 fixture.detectChanges 来触发数据绑定更新。 默认值是 false,喜欢对测试行为进行精细控制的测试者一般保持它为 false。Set this to true when you want the fixture to detect changes automatically. When autodetect is true, the test fixture calls detectChanges immediately after creating the component. Then it listens for pertinent zone events and calls detectChanges accordingly. When your test code modifies component property values directly, you probably still have to call fixture.detectChanges to trigger data binding updates. The default is false. Testers who prefer fine control over test behavior tend to keep it false. | ||
checkNoChanges | 运行一次变更检测来确认没有待处理的变化。如果有未处理的变化,它将抛出一个错误。Do a change detection run to make sure there are no pending changes. Throws an exceptions if there are. | ||
isStable | 如果 fixture 当前是稳定的,则返回 true。如果有异步任务没有完成,则返回 false。If the fixture is currently stable, returns true. If there are async tasks that have not completed, returns false. | ||
whenStable | 返回一个 Promise ,在 fixture 稳定时解析。 要想在完成了异步活动或异步变更检测之后再继续测试,可以对那个 Promise 对象进行挂钩。参阅 whenStable。Returns a promise that resolves when the fixture is stable. To resume testing after completion of asynchronous activity or asynchronous change detection, hook that promise. See whenStable. | ||
destroy | 触发组件的销毁。Trigger component destruction. |
# DebugElement
DebugElement
提供了对组件的 DOM 的访问。
fixture.debugElement
返回测试根组件的 DebugElement
,通过它你可以访问(查询)fixture 的整个元素和组件子树。
下面是 DebugElement
最有用的成员,以使用频率排序。
成员 | Members | 详情 | Details |
---|---|---|---|
nativeElement | 与浏览器中 DOM 元素对应(WebWorkers 时,值为 null)。The corresponding DOM element in the browser (null for WebWorkers). | ||
query | 调用 query(predicate: Predicate<DebugElement> ) 会在子树的任意深度中查找并返回能和谓词函数匹配的第一个 DebugElement。Calling query(predicate: Predicate<DebugElement> ) returns the first DebugElement that matches the predicate at any depth in the subtree. | ||
queryAll | 调用 queryAll(predicate: Predicate<DebugElement> ) 会在子树的任意深度中查找能和谓词函数匹配的所有 DebugElement。Calling queryAll(predicate: Predicate<DebugElement> ) returns all DebugElements that matches the predicate at any depth in subtree. | ||
injector | 宿主依赖注入器。比如,根元素的组件实例注入器。The host dependency injector. For example, the root element's component instance injector. | ||
componentInstance | 元素自己的组件实例(如果有)。The element's own component instance, if it has one. | ||
context | 为元素提供父级上下文的对象。通常是控制该元素的祖级组件实例。 当一个元素被 *ngFor 重复,它的上下文为 NgForOf,它的 $implicit 属性值是该行的实例值。比如,*ngFor="let hero of heroes" 里的 hero。An object that provides parent context for this element. Often an ancestor component instance that governs this element. When an element is repeated within *ngFor, the context is an NgForOf whose $implicit property is the value of the row instance value. For example, the hero in *ngFor="let hero of heroes". | ||
children | DebugElement 的直接子元素。可以通过继续深入 children 来遍历这棵树。 DebugElement 还有 childNodes,即 DebugNode 对象列表。DebugElement 从 DebugNode 对象衍生,而且通常节点(node)比元素多。测试者通常忽略普通节点。The immediate DebugElement children. Walk the tree by descending through children. DebugElement also has childNodes, a list of DebugNode objects. DebugElement derives from DebugNode objects and there are often more nodes than elements. Testers can usually ignore plain nodes. | ||
parent | DebugElement 的父级。如果 DebugElement 是根元素,parent 为 null。The DebugElement parent. Null if this is the root element. | ||
name | 元素的标签名字,如果它是一个元素的话。The element tag name, if it is an element. | ||
triggerEventHandler | 如果在该元素的 listeners 集合中有相应的监听器,就根据名字触发这个事件。第二个参数是该处理器函数所需的事件对象。参阅 triggerEventHandler。 如果事件缺乏监听器,或者有其它问题,考虑调用 nativeElement.dispatchEvent(eventObject)。Triggers the event by its name if there is a corresponding listener in the element's listeners collection. The second parameter is the event object expected by the handler. See triggerEventHandler. If the event lacks a listener or there's some other problem, consider calling nativeElement.dispatchEvent(eventObject). | ||
listeners | 元素的 @Output 属性以及/或者元素的事件属性所附带的回调函数。The callbacks attached to the component's @Output properties and/or the element's event properties. | ||
providerTokens | 组件注入器的查询令牌。包括组件自己的令牌和组件的 providers 元数据中列出来的令牌。This component's injector lookup tokens. Includes the component itself plus the tokens that the component lists in its providers metadata. | ||
source | source 是在源组件模板中查询这个元素的处所。Where to find this element in the source component template. | ||
references | 与模板本地变量(比如 #foo)关联的词典对象,关键字与本地变量名字配对。Dictionary of objects associated with template local variables (for example, #foo), keyed by the local variable name. |
DebugElement.query(predicate)
和 DebugElement.queryAll(predicate)
方法接受一个条件方法,它过滤源元素的子树,返回匹配的 DebugElement
。
这个条件方法是任何接受一个 DebugElement
并返回真值的方法。下面的例子查询所有拥有名为 content
的模块本地变量的所有 DebugElement
:
app/demo/demo.testbed.spec.ts
// Filter for DebugElements with a #content reference
const contentRefs = el.queryAll( de => de.references['content']);
Angular 的 By
类为常用条件方法提供了三个静态方法:
静态方法 | Static method | 详情 | Details |
---|---|---|---|
By.all | 返回所有元素Return all elements | ||
By.css(selector) | 返回符合 CSS 选择器的元素Return elements with matching CSS selectors | ||
By.directive(directive) | 返回 Angular 能匹配一个指令类实例的所有元素Return elements that Angular matched to an instance of the directive class |
app/hero/hero-list.component.spec.ts
// Can find DebugElement either by css selector or by directive
const h2 = fixture.debugElement.query(By.css('h2'));
const directive = fixture.debugElement.query(By.directive(HighlightDirective));