NOTE: 本指南正陸續更新為 Vitest 版本,目前部分工具 API 的說明與範例仍以 Karma/Jasmine 的情境呈現。我們正積極提供 Vitest 的對等內容與更新後的指引。
本頁說明最實用的 Angular 測試功能。
Angular 測試工具包括 TestBed、ComponentFixture,以及一些控制測試環境的函式。
TestBed 與 ComponentFixture 類別另有專節說明。
以下是獨立函式的摘要,依可能的實用程度排序:
| Function | Details |
|---|---|
[inject] |
將目前 TestBed 注入器中的一或多個服務注入測試函式。它無法注入由元件本身提供的服務。請參閱 debugElement.injector 的討論。 |
getTestBed |
取得 TestBed 的目前實例。通常不需要使用,因為 TestBed 類別的靜態類別方法一般就已足夠。TestBed 實例公開了一些較少使用、且沒有靜態方法版本的成員。 |
如需處理複雜的非同步情境,或測試舊版以 Zone.js 為基礎的應用程式,請參閱 Zone.js 測試工具 指南。
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 的_全域_實例。
在內部,所有靜態方法都是目前執行期 TestBed 實例的方法的包裝,而該實例也會由 getTestBed() 函式傳回。
請在 beforeEach() _內_呼叫 TestBed 方法,確保每個個別測試開始前都是全新狀態。
以下是最重要的靜態方法,依可能的實用程度排序。
| Methods | Details |
|---|---|
configureTestingModule |
測試墊片會建立初始測試環境與預設的測試模組。預設測試模組設定了基本的宣告式成員,以及每位測試者都需要的一些 Angular 服務替代實作。 呼叫 configureTestingModule,可以加入與移除匯入、宣告(元件、指令與管道)及 providers,為特定的測試組調整測試模組設定。 |
compileComponents |
在你完成測試模組的設定後,以非同步方式編譯該模組。如果測試模組的_任何_元件具有非同步載入的資源(例如 @defer 區塊),你必須呼叫這個方法。 |
createComponent<T> |
根據目前的 TestBed 設定,建立型別為 T 的元件實例。呼叫 createComponent 之後,TestBed 設定會在目前規格的執行期間凍結。 |
overrideComponent |
取代指定元件類別的中繼資料,該元件可能深藏在內層模組之中。 |
overrideDirective |
取代指定指令類別的中繼資料,該指令可能深藏在內層模組之中。 |
overridePipe |
取代指定管道類別的中繼資料,該管道可能深藏在內層模組之中。 |
overrideModule |
取代指定的 NgModule。請記住,模組可以匯入其他模組。overrideModule 方法可以深入目前的測試模組,修改其中某個內層模組。 |
inject |
從目前的 TestBed 注入器取得服務。inject 函式通常就足以勝任此用途。但若 inject 無法提供該服務,就會擲出錯誤。如果該服務是選用的,該怎麼辦? TestBed.inject() 方法接受一個選用的第二個參數,也就是 Angular 找不到 provider 時要傳回的物件(此例為 null):expect(TestBed.inject(NotProvided, null)).toBeNull(); 呼叫 TestBed.inject 之後,TestBed 設定會在目前規格的執行期間凍結。 |
initTestEnvironment |
為整個測試執行初始化測試環境。 測試墊片會為你呼叫它,所以你幾乎不需要自己呼叫。 這個方法只能呼叫_恰好一次_。若要在測試執行中途變更這個預設值,請先呼叫 resetTestEnvironment。指定一個預設的 Angular 測試模組與一個 PlatformRef。非瀏覽器平台的替代方案可在 @angular/platform-<platform_name>/testing 這個一般形式下取得。 |
resetTestEnvironment |
重設初始測試環境,包括預設的測試模組。 |
少數 TestBed 實例方法沒有對應的靜態 TestBed _類別_方法。
這些方法很少需要使用。
ComponentFixture
TestBed.createComponent<T> 會建立元件 T 的實例,並為該元件傳回強型別的 ComponentFixture。
ComponentFixture 的屬性與方法提供對元件、其 DOM 表示方式,以及其 Angular 環境各方面的存取。
ComponentFixture 屬性
以下是對測試者最重要的屬性,依可能的實用程度排序。
| Properties | Details |
|---|---|
componentInstance |
由 TestBed.createComponent 建立的元件類別實例。 |
debugElement |
與元件根元素相關聯的 DebugElement。debugElement 讓你在測試與除錯期間深入了解元件及其 DOM 元素。這是測試者的關鍵屬性。最值得關注的成員在下文說明。 |
nativeElement |
位於元件根部的原生 DOM 元素。 |
changeDetectorRef |
元件宿主檢視的 ChangeDetectorRef,不是元件本身的。請參閱在 TestBed 中使用 Zoneless。 |
ComponentFixture 方法
fixture 方法會讓 Angular 對元件樹執行某些工作。 呼叫這些方法,可以觸發 Angular 行為以回應模擬的使用者動作。
以下是最實用的方法。
| Methods | Details |
|---|---|
detectChanges |
為元件觸發一個變更偵測週期。 呼叫它來初始化元件(它會呼叫 ngOnInit),以及在測試程式碼變更元件的資料繫結屬性值之後呼叫。Angular 無法得知你已變更 personComponent.name,在你呼叫 detectChanges 之前,不會更新 name 繫結。之後會執行 checkNoChanges,確認沒有循環更新,除非以 detectChanges(false) 的方式呼叫; |
autoDetectChanges |
當你希望 fixture 自動偵測變更時,將它設為 true。當自動偵測為 true 時,測試 fixture 會在建立元件後立即呼叫 detectChanges。接著它會監聽相關的 zone 事件,並相應地呼叫 detectChanges。當你的測試程式碼直接修改元件屬性值時,你可能仍然必須呼叫 fixture.detectChanges 來觸發資料繫結更新。使用 zoneless 變更偵測時( TestBed 的預設值),預設為 true;使用以 Zone 為基礎的變更偵測時,預設為 false。 |
checkNoChanges |
執行一次變更偵測,確保沒有待處理的變更。若有變更則擲出例外。 |
isStable |
若 fixture 目前_穩定_,傳回 true。若有尚未完成的非同步工作,傳回 false。 |
whenStable |
傳回一個在 fixture 穩定時完成的 promise。 若要在非同步活動或非同步變更偵測完成後繼續測試,請掛接該 promise。請參閱 whenStable。 |
destroy |
觸發元件銷毀。 |
DebugElement
DebugElement 提供對元件 DOM 表示方式的關鍵洞察。
從測試根元件由 fixture.debugElement 傳回的 DebugElement,你可以走訪(並查詢)fixture 的整個元素與元件子樹。
以下是對測試者最實用的 DebugElement 成員,依大約的實用程度排序:
| Members | Details |
|---|---|
nativeElement |
瀏覽器中對應的 DOM 元素 |
query |
呼叫 query(predicate: Predicate<DebugElement>),傳回子樹中任意深度第一個符合述詞的 DebugElement。 |
queryAll |
呼叫 queryAll(predicate: Predicate<DebugElement>),傳回子樹中任意深度所有符合述詞的 DebugElement。 |
injector |
宿主的相依性注入器。例如,根元素的元件實例注入器。 |
componentInstance |
元素自身的元件實例(如果有的話)。 |
context |
提供此元素父層上下文的物件。通常是掌管此元素的祖先元件實例。 當元素在 @for 區塊內重複時,其 context 是一個 RepeaterContext,其 $implicit 屬性是該列實例的值。例如 @for(hero of heroes; ...) 中的 hero。 |
children |
直接的 DebugElement 子元素。透過 children 逐層往下走訪整棵樹。DebugElement 也有 childNodes,是 DebugNode 物件的清單。DebugElement 源自 DebugNode 物件,而且節點的數量往往比元素多。測試者通常可以忽略純節點。 |
parent |
DebugElement 的父元素。若這是根元素,則為 Null。 |
name |
元素的標籤名稱(如果它是元素的話)。 |
triggerEventHandler |
若元素的 listeners 集合中有對應的監聽器,則依名稱觸發該事件。第二個參數是處理常式預期的_事件物件_。 若事件缺少監聽器,或有其他問題,請考慮呼叫 nativeElement.dispatchEvent(eventObject)。 |
listeners |
附加在元件 @Output 屬性及/或元素事件屬性上的回呼。 |
providerTokens |
此元件的注入器查找權杖。包括元件本身,加上元件在其 providers 中繼資料中所列的權杖。 |
references |
與範本區域變數相關聯的物件字典(例如 #foo),以區域變數名稱為鍵。 |
DebugElement.query(predicate) 與 DebugElement.queryAll(predicate) 方法接受一個述詞,用來篩選來源元素的子樹,找出符合的 DebugElement。
述詞可以是任何接受 DebugElement 並傳回_真值_的方法。
下列範例找出所有具有名為 "content" 的範本區域變數參照的 DebugElement:
// Filter for DebugElements with a #content reference
const contentRefs = el.queryAll((de) => de.references['content']);
Angular 的 By 類別有三個靜態方法,用於常見的述詞:
| Static method | Details |
|---|---|
By.all |
傳回所有元素 |
By.css(selector) |
傳回符合 CSS 選擇器的元素 |
By.directive(directive) |
傳回 Angular 對應到該指令類別實例的元素 |