填寫這份《一分鐘調查》,幫我們(開發組)做得更好!去填寫Home

測試實用工具 API

Testing Utility APIs

本頁面描述了一些最有用的 Angular 測試特性。

This page describes the most useful Angular testing features.

Angular 測試實用工具包括 TestBedComponentFixture 以及一些控制測試環境的函式。 TestBedComponentFixture 類別是單獨介紹的。

The Angular testing utilities include the TestBed, the ComponentFixture, and a handful of functions that control the test environment. The TestBed and ComponentFixture classes are covered separately.

下面是一些獨立函式的摘要,以使用頻率排序:

Here's a summary of the stand-alone functions, in order of likely utility:

函式

Function

說明

Description

waitForAsync

在一個特殊的 async 測試區域中執行測試(it)的函式體或準備函式(beforeEach)。 參閱前面的討論

Runs the body of a test (it) or setup (beforeEach) function within a special async test zone. See discussion above.

fakeAsync

在一個特殊的 fakeAsync 測試區域中執行測試(it)的函式體,以便啟用線性風格的控制流。 參閱前面的討論

Runs the body of a test (it) within a special fakeAsync test zone, enabling a linear control flow coding style. See discussion above.

tick

透過在 fakeAsync 測試區域中重新整理定時器和微任務(micro-task)佇列來模擬時間的流逝以及非同步活動的完成。

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.

好奇和執著的讀者可能會喜歡這篇長部落格: "Tasks, microtasks, queues and schedules".

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 discussion above.

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 測試程式以正在執行的計時器事件任務(排隊中的 setTimeOutsetInterval 的回呼(Callback))結束時, 測試會失敗,並顯示一條明確的錯誤資訊。

When a fakeAsync() test ends with pending timer event tasks (queued setTimeOut and setInterval callbacks), the test fails with a clear error message.

一般來講,測試程式應該以無排隊任務結束。 當待執行計時器任務存在時,呼叫 discardPeriodicTasks 來觸發任務佇列,防止該錯誤發生。

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 測試程式以待執行微任務(比如未解析的承諾)結束時,測試會失敗並顯示明確的錯誤資訊。

When a fakeAsync() test ends with pending micro-tasks such as unresolved promises, the test fails with a clear error message.

一般來說,測試應該等待微任務結束。 當待執行微任務存在時,呼叫 flushMicrotasks 來觸發微任務佇列,防止該錯誤發生。

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 class summary

TestBed 類別是 Angular 測試工具的主要類別之一。它的 API 很龐大,可能有點過於複雜,直到你一點一點的探索它們。 閱讀本章前面的部分,瞭解了基本的知識以後,再試著瞭解完整 API。

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, a little at a time. Read the early part of this guide first to get the basics before trying to absorb the full API.

傳給 configureTestingModule 的模組定義是 @NgModule 元資料屬性的子集。

The module definition passed to configureTestingModule is a subset of the @NgModule metadata properties.

type TestModuleMetadata = { providers?: any[]; declarations?: any[]; imports?: any[]; schemas?: Array<SchemaMetadata | any[]>; };
      
      type TestModuleMetadata = {
  providers?: any[];
  declarations?: any[];
  imports?: any[];
  schemas?: Array<SchemaMetadata | any[]>;
};
    

每一個過載方法接受一個 MetadataOverride<T>,這裡 T 是適合這個方法的元資料型別,也就是 @NgModule@Component@Directive 或者 @Pipe 的引數。

Each override method takes a MetadataOverride<T> where T is the kind of metadata appropriate to the method, that is, the parameter of an @NgModule, @Component, @Directive, or @Pipe.

type MetadataOverride<T> = { add?: Partial<T>; remove?: Partial<T>; set?: Partial<T>; };
      
      type MetadataOverride<T> = {
  add?: Partial<T>;
  remove?: Partial<T>;
  set?: Partial<T>;
};
    

TestBed 的 API 包含了一系列靜態類別方法,它們更新或者參考全域性TestBed 實例。

The TestBed API consists of static class methods that either update or reference a global instance of the TestBed.

在內部,所有靜態方法在 getTestBed() 函式返回的當前執行時間的 TestBed 實例上都有對應的方法。

Internally, all static methods cover methods of the current runtime TestBed instance, which is also returned by the getTestBed() function.

BeforeEach() 內呼叫 TestBed 方法,以確保在執行每個單獨測試時,都有嶄新的開始。

Call TestBed methods within a beforeEach() to ensure a fresh start before each individual test.

這裡列出了最重要的靜態方法,以使用頻率排序:

Here are the most important static methods, in order of likely utility.

方法

Methods

說明

Description

configureTestingModule

測試墊片(karma-test-shim, browser-test-shim)建立了初始測試環境和預設測試模組。 預設測試模組是使用基本宣告和一些 Angular 服務替代品,它們是所有測試程式都需要的。

The testing shims (karma-test-shim, browser-test-shim) establish the initial test environment and a default testing module. The default testing module is configured with basic declaratives and some Angular service substitutes that every tester needs.

呼叫 configureTestingModule 來為一套特定的測試定義測試模組配置,新增和刪除匯入、(元件、指令和管道的)宣告和服務提供者。

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.

compileComponents

在配置好測試模組之後,非同步編譯它。 如果測試模組中的任何一個元件具有 templateUrlstyleUrls,那麼你必須呼叫這個方法,因為獲取元件的範本或樣式檔案必須是非同步的。 參閱前面的討論

Compile the testing module asynchronously after you've finished configuring it. You must call this method if any of the testing module components have a templateUrl or styleUrls because fetching component template and style files is necessarily asynchronous. See above.

呼叫完 compileComponents 之後,TestBed 的配置就會在當前測試期間被凍結。

After calling compileComponents, the TestBed configuration is frozen for the duration of the current spec.

createComponent

基於當前 TestBed 的配置建立一個型別為 T 的元件實例。 一旦呼叫,TestBed 的配置就會在當前測試期間被凍結。

Create an instance of a component of type T based on the current TestBed configuration. After calling compileComponent, the TestBed configuration is frozen for the duration of the current spec.

overrideModule

替換指定的 NgModule 的元資料。回想一下,模組可以匯入其它模組。 overrideModule 方法可以深入到當前測試模組深處,修改其中一個內部模組。

Replace metadata for the given NgModule. Recall that modules can import other modules. The overrideModule method can reach deeply into the current testing module to modify one of these inner modules.

overrideComponent

替換指定元件類別的元資料,該元件類別可能巢狀在一個很深的內部模組中。

Replace metadata for the given component class, which could be nested deeply within an inner module.

overrideDirective

替換指定指令類別的元資料,該指令可能巢狀在一個很深的內部模組中。

Replace metadata for the given directive class, which could be nested deeply within an inner module.

overridePipe

替換指定管道類別的元資料,該管道可能巢狀在一個很深的內部模組中。

Replace metadata for the given pipe class, which could be nested deeply within an inner module.

inject

從當前 TestBed 注入器獲取一個服務。

Retrieve a service from the current TestBed injector.

inject 函式通常都能勝任這項工作,但是如果它沒法提供該服務時就會丟擲一個異常。

The inject function is often adequate for this purpose. But inject throws an error if it can't provide the service.

如果該服務是可選的呢?

What if the service is optional?

TestBed.inject() 方法可以接受可選的第二引數,當 Angular 找不到指定的服務提供者時,就會返回該物件(下面這個例子中是 null ):

The TestBed.inject() method takes an optional second parameter, the object to return if Angular can't find the provider (null in this example):

service = TestBed.inject(NotProvided, null); // service is null
app/demo/demo.testbed.spec.ts
      
      service = TestBed.inject(NotProvided, null); // service is null
    

呼叫了 TestBed.inject 之後然後透過呼叫,TestBed 的配置就會在當前測試期間被凍結。

After calling TestBed.inject, the TestBed configuration is frozen for the duration of the current spec.

initTestEnvironment

為整套測試的執行初始化測試環境。

Initialize the testing environment for the entire test run.

測試墊片(karma-test-shim, browser-test-shim)會為你呼叫它,所以你很少需要自己呼叫它。

The testing shims (karma-test-shim, browser-test-shim) call it for you so there is rarely a reason for you to call it yourself.

這個方法只能被呼叫一次。如果確實需要在測試程式執行期間改變這個預設設定,那麼先呼叫 resetTestEnvironment

You may call this method exactly once. If you must change this default in the middle of your test run, call resetTestEnvironment first.

指定 Angular 編譯器工廠,PlatformRef,和預設 Angular 測試模組。 以 @angular/platform-<platform_name>/testing/<platform_name> 的形式提供非瀏覽器平臺的替代品。

Specify the Angular compiler factory, a PlatformRef, and a default Angular testing module. Alternatives for non-browser platforms are available in the general form @angular/platform-<platform_name>/testing/<platform_name>.

resetTestEnvironment

重設初始測試環境,包括預設測試模組在內。

Reset the initial test environment, including the default testing module.

少數 TestBed 實例方法沒有對應的靜態方法。它們很少被使用。

A few of the TestBed instance methods are not covered by static TestBed class methods. These are rarely needed.

ComponentFixture 類別

The ComponentFixture

TestBed.createComponent<T> 會建立一個元件 T 的實例,並為該元件返回一個強型別的 ComponentFixture

The TestBed.createComponent<T> creates an instance of the component T and returns a strongly typed ComponentFixture for that component.

ComponentFixture 的屬性和方法提供了對元件、它的 DOM 和它的 Angular 環境方面的訪問。

The ComponentFixture properties and methods provide access to the component, its DOM representation, and aspects of its Angular environment.

ComponentFixture 的屬性

ComponentFixture properties

下面是對測試最重要的屬性,以使用頻率排序:

Here are the most important properties for testers, in order of likely utility.

屬性

Properties

說明

Description

componentInstance

TestBed.createComponent 建立的元件類別實例。

The instance of the component class created by TestBed.createComponent.

debugElement

與元件根元素關聯的 DebugElement

The DebugElement associated with the root element of the component.

debugElement 提供了在測試和除錯期間深入探查元件及其 DOM 元素的功能。 它對於測試者是一個極其重要的屬性。它的大多數主要成員在後面都有講解。

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

The ChangeDetectorRef for the component.

在測試一個擁有 ChangeDetectionStrategy.OnPush 的元件,或者在元件的變化測試在你的程式控制下時,ChangeDetectorRef 是最重要的。

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 的方法

ComponentFixture methods

fixture 方法使 Angular 對元件樹執行某些任務。 在觸發 Angular 行為來模擬的使用者行為時,呼叫這些方法。

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.

下面是對測試最有用的方法。

Here are the most useful methods for testers.

方法

Methods

說明

Description

detectChanges

為元件觸發一輪變化檢查。

Trigger a change detection cycle for the component.

呼叫它來初始化元件(它呼叫 ngOnInit)。或者在你的測試程式碼改變了元件的資料繫結屬性值後呼叫它。 Angular 不能檢測到你已經改變了 personComponent.name 屬性,也不會更新 name 的繫結,直到你呼叫了 detectChanges

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.

之後,執行 checkNoChanges,來確認沒有迴圈更新,除非它被這樣呼叫:detectChanges(false)

Runs checkNoChanges afterwards to confirm that there are no circular updates unless called as detectChanges(false);

autoDetectChanges

如果你希望這個夾具自動檢測變更,就把這個設定為 true

Set this to true when you want the fixture to detect changes automatically.

當自動檢測開啟時,測試 fixture 監聽 zone 事件,並呼叫 detectChanges。 當你的測試程式碼直接修改了元件屬性值時,你還是要呼叫 fixture.detectChanges 來觸發資料繫結更新。

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.

預設值是 false,喜歡對測試行為進行精細控制的測試者一般保持它為 false

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

返回一個承諾,在 fixture 穩定時解析。

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 above.

destroy

觸發元件的銷燬。

Trigger component destruction.

DebugElement

DebugElement 提供了對元件的 DOM 的訪問。

The DebugElement provides crucial insights into the component's DOM representation.

fixture.debugElement 返回測試根元件的 DebugElement,透過它你可以訪問(查詢)fixture 的整個元素和元件子樹。

From the test root component's DebugElement returned by fixture.debugElement, you can walk (and query) the fixture's entire element and component subtrees.

下面是 DebugElement 最有用的成員,以使用頻率排序。

Here are the most useful DebugElement members for testers, in approximate order of utility:

成員

Member

說明

Description

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

為元素提供父級上下文的物件。 通常是控制該元素的祖級元件實例。

An object that provides parent context for this element. Often an ancestor component instance that governs this element.

當一個元素被 *ngFor 重複,它的上下文為 NgForRow,它的 $implicit 屬性值是該行的實例值。 比如,*ngFor="let hero of heroes" 裡的 hero

When an element is repeated within *ngFor, the context is an NgForRow whose $implicit property is the value of the row instance value. For example, the hero in *ngFor="let hero of heroes".

children

DebugElement 的直接子元素。可以透過繼續深入 children 來遍歷這棵樹。

The immediate DebugElement children. Walk the tree by descending through children.

DebugElement 還有 childNodes,即 DebugNode 物件列表。 DebugElementDebugNode 物件衍生,而且通常節點(node)比元素多。測試者通常忽略赤裸節點。

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 集合中有相應的監聽器,就根據名字觸發這個事件。 第二個引數是該處理器函式所需的事件物件。參閱前面

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 above.

如果事件缺乏監聽器,或者有其它問題,考慮呼叫 nativeElement.dispatchEvent(eventObject)

If the event lacks a listener or there's some other problem, consider calling nativeElement.dispatchEvent(eventObject).

listeners

元素的 @Output 屬性以及/或者元素的事件屬性所附帶的回呼(Callback)函式。

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 (e.g. #foo), keyed by the local variable name.

DebugElement.query(predicate)DebugElement.queryAll(predicate) 方法接受一個條件方法, 它過濾源元素的子樹,返回匹配的 DebugElement

The DebugElement.query(predicate) and DebugElement.queryAll(predicate) methods take a predicate that filters the source element's subtree for matching DebugElement.

這個條件方法是任何接受一個 DebugElement 並返回真值的方法。 下面的例子查詢所有擁有名為 content 的模組本地變數的所有 DebugElement

The predicate is any method that takes a DebugElement and returns a truthy value. The following example finds all DebugElements with a reference to a template local variable named "content":

// Filter for DebugElements with a #content reference const contentRefs = el.queryAll( de => de.references.content);
app/demo/demo.testbed.spec.ts
      
      // Filter for DebugElements with a #content reference
const contentRefs = el.queryAll( de => de.references.content);
    

Angular 的 By 類別為常用條件方法提供了三個靜態方法:

The Angular By class has three static methods for common predicates:

  • By.all - 返回所有元素

    By.all - return all elements.

  • By.css(selector) - 返回符合 CSS 選擇器的元素。

    By.css(selector) - return elements with matching CSS selectors.

  • By.directive(directive) - 返回 Angular 能匹配一個指令類別實例的所有元素。

    By.directive(directive) - return elements that Angular matched to an instance of the directive class.

// 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));
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));