Angular 測試工具API

2022-07-08 09:41 更新

測試實(shí)用工具 API

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

Angular 測試實(shí)用工具包括 ?TestBed?、?ComponentFixture ?以及一些控制測試環(huán)境的函數(shù)。?TestBed ?和 ?ComponentFixture ?類是單獨(dú)介紹的。

下面是一些獨(dú)立函數(shù)的摘要,以使用頻率排序:

函數(shù)

詳情

waitForAsync

在一個(gè)特殊的async 測試區(qū)域中運(yùn)行測試(?it?)的函數(shù)體或準(zhǔn)備函數(shù)(?beforeEach?)。

fakeAsync

在一個(gè)特殊的fakeAsync 測試區(qū)域中運(yùn)行測試(?it?)的函數(shù)體,以便啟用線性風(fēng)格的控制流。

tick

通過在 fakeAsync 測試區(qū)域中刷新定時(shí)器和微任務(wù)(micro-task)隊(duì)列來仿真時(shí)間的流逝以及異步活動(dòng)的完成。

好奇和執(zhí)著的讀者可能會喜歡這篇長博客:
Tasks, microtasks, queues and schedules

接受一個(gè)可選參數(shù),它可以把虛擬時(shí)鐘往前推進(jìn)特定的微秒數(shù)。清除調(diào)度到那個(gè)時(shí)間幀中的異步活動(dòng)。

inject

從當(dāng)前的 TestBed 注入器中把一個(gè)或多個(gè)服務(wù)注入到一個(gè)測試函數(shù)中。它不能用于注入組件自身提供的服務(wù)。

discardPeriodicTasks 當(dāng) ?fakeAsync ?測試程序以正在運(yùn)行的計(jì)時(shí)器事件任務(wù)(排隊(duì)中的 ?setTimeOut ?和 ?setInterval ?的回調(diào))結(jié)束時(shí),測試會失敗,并顯示一條明確的錯(cuò)誤信息。
一般來講,測試程序應(yīng)該以無排隊(duì)任務(wù)結(jié)束。當(dāng)待執(zhí)行計(jì)時(shí)器任務(wù)存在時(shí),調(diào)用 ?discardPeriodicTasks ?來觸發(fā)任務(wù)隊(duì)列,防止該錯(cuò)誤發(fā)生。
flushMicrotasks

當(dāng) ?fakeAsync ?測試程序以待執(zhí)行微任務(wù)(比如未解析的承諾)結(jié)束時(shí),測試會失敗并顯示明確的錯(cuò)誤信息。

一般來說,測試應(yīng)該等待微任務(wù)結(jié)束。當(dāng)待執(zhí)行微任務(wù)存在時(shí),調(diào)用 ?flushMicrotasks ?來觸發(fā)微任務(wù)隊(duì)列,防止該錯(cuò)誤發(fā)生。

ComponentFixtureAutoDetect

一個(gè)服務(wù)提供者令牌,用于開啟自動(dòng)變更檢測。

getTestBed 獲取當(dāng)前 ?TestBed ?實(shí)例。通常用不上,因?yàn)??TestBed ?的靜態(tài)類方法已經(jīng)夠用。?TestBed ?實(shí)例有一些很少需要用到的方法,它們沒有對應(yīng)的靜態(tài)方法。

TestBed 類摘要

?TestBed ?類是 Angular 測試工具的主要類之一。它的 API 很龐大,可能有點(diǎn)過于復(fù)雜,直到你一點(diǎn)一點(diǎn)的探索它們。

傳給 ?configureTestingModule ?的模塊定義是 ?@NgModule? 元數(shù)據(jù)屬性的子集。

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

每一個(gè)重載方法接受一個(gè) ?MetadataOverride<T>?,這里 ?T? 是適合這個(gè)方法的元數(shù)據(jù)類型,也就是 ?@NgModule?、?@Component?、?@Directive? 或者 ?@Pipe? 的參數(shù)。

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

?TestBed ?的 API 包含了一系列靜態(tài)類方法,它們更新或者引用全局的 ?TestBed ?實(shí)例。

在內(nèi)部,所有靜態(tài)方法在 ?getTestBed()? 函數(shù)返回的當(dāng)前運(yùn)行時(shí)間的 ?TestBed ?實(shí)例上都有對應(yīng)的方法。

在 ?BeforeEach()? 內(nèi)調(diào)用 ?TestBed ?方法,以確保在運(yùn)行每個(gè)單獨(dú)測試時(shí),都有嶄新的開始。

這里列出了最重要的靜態(tài)方法,以使用頻率排序。

方法

詳情

configureTestingModule

測試墊片(karma-test-shimbrowser-test-shim)創(chuàng)建了初始測試環(huán)境和默認(rèn)測試模塊。默認(rèn)測試模塊是使用基本聲明和一些 Angular 服務(wù)替代品,它們是所有測試程序都需要的。
調(diào)用 configureTestingModule 來為一套特定的測試定義測試模塊配置,添加和刪除導(dǎo)入、(組件、指令和管道的)聲明和服務(wù)提供者。

compileComponents

在配置好測試模塊之后,異步編譯它。如果測試模塊中的任何一個(gè)組件具有 templateUrl 或 styleUrls,那么你必須調(diào)用這個(gè)方法,因?yàn)楂@取組件的模板或樣式文件必須是異步的。
調(diào)用完 compileComponents 之后,TestBed 的配置就會在當(dāng)前測試期間被凍結(jié)。

createComponent<T>

基于當(dāng)前 TestBed 的配置創(chuàng)建一個(gè)類型為 T 的組件實(shí)例。調(diào)用 createComponent 之后,TestBed 的配置就會在當(dāng)前測試期間被凍結(jié)。

overrideModule

替換指定的 NgModule 的元數(shù)據(jù)?;叵胍幌?,模塊可以導(dǎo)入其它模塊。overrideModule 方法可以深入到當(dāng)前測試模塊深處,修改其中一個(gè)內(nèi)部模塊。

overrideComponent

替換指定組件類的元數(shù)據(jù),該組件類可能嵌套在一個(gè)很深的內(nèi)部模塊中。

overrideDirective

替換指定指令類的元數(shù)據(jù),該指令可能嵌套在一個(gè)很深的內(nèi)部模塊中。

overridePipe

替換指定管道類的元數(shù)據(jù),該管道可能嵌套在一個(gè)很深的內(nèi)部模塊中。

inject

從當(dāng)前 TestBed 注入器獲取一個(gè)服務(wù)。inject 函數(shù)通常都能勝任這項(xiàng)工作,但是如果它沒法提供該服務(wù)時(shí)就會拋出一個(gè)異常。
如果該服務(wù)是可選的呢?
TestBed.inject() 方法可以接受可選的第二參數(shù),當(dāng) Angular 找不到指定的服務(wù)提供者時(shí),就會返回該對象(下面這個(gè)例子中是 null):

expect(TestBed.inject(NotProvided, null)).toBeNull();
調(diào)用了 TestBed.inject 之后然后通過調(diào)用,TestBed 的配置就會在當(dāng)前測試期間被凍結(jié)。
initTestEnvironment

為整套測試的運(yùn)行初始化測試環(huán)境。
測試墊片(karma-test-shimbrowser-test-shim)會為你調(diào)用它,所以你很少需要自己調(diào)用它。
這個(gè)方法只能被調(diào)用一次。如果確實(shí)需要在測試程序運(yùn)行期間改變這個(gè)默認(rèn)設(shè)置,那么先調(diào)用 resetTestEnvironment。
指定 Angular 編譯器工廠,PlatformRef,和默認(rèn) Angular 測試模塊。以 @angular/platform-<platform_name>/testing/<platform_name> 的形式提供非瀏覽器平臺的替代品。

resetTestEnvironment

重設(shè)初始測試環(huán)境,包括默認(rèn)測試模塊在內(nèi)。

少數(shù) ?TestBed ?實(shí)例方法沒有對應(yīng)的靜態(tài)方法。它們很少被使用。

ComponentFixture 類

?TestBed.createComponent<T>? 會創(chuàng)建一個(gè)組件 ?T? 的實(shí)例,并為該組件返回一個(gè)強(qiáng)類型的 ?ComponentFixture?。

?ComponentFixture ?的屬性和方法提供了對組件、它的 DOM 和它的 Angular 環(huán)境方面的訪問。

ComponentFixture 的屬性

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

屬性

詳情

componentInstance

被 TestBed.createComponent 創(chuàng)建的組件類實(shí)例。

debugElement

與組件根元素關(guān)聯(lián)的 DebugElement。
debugElement 提供了在測試和調(diào)試期間深入探查組件及其 DOM 元素的功能。它對于測試者是一個(gè)極其重要的屬性。

nativeElement

組件的原生根 DOM 元素。

changeDetectorRef

組件的 ChangeDetectorRef。
在測試一個(gè)擁有 ChangeDetectionStrategy.OnPush 的組件,或者在組件的變化測試在你的程序控制下時(shí),ChangeDetectorRef 是最重要的。

ComponentFixture 方法

fixture 方法使 Angular 對組件樹執(zhí)行某些任務(wù)。在觸發(fā) Angular 行為來模擬的用戶行為時(shí),調(diào)用這些方法。

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

方法

詳情

detectChanges

為組件觸發(fā)一輪變化檢查。
調(diào)用它來初始化組件(它調(diào)用 ngOnInit)?;蛘咴谀愕臏y試代碼改變了組件的數(shù)據(jù)綁定屬性值后調(diào)用它。Angular 不能檢測到你已經(jīng)改變了 personComponent.name 屬性,也不會更新 name 的綁定,直到你調(diào)用了 detectChanges。
之后,運(yùn)行 checkNoChanges,來確認(rèn)沒有循環(huán)更新,除非它被這樣調(diào)用:detectChanges(false)

autoDetectChanges

如果你希望這個(gè)夾具自動(dòng)檢測變更,就把這個(gè)設(shè)置為 true
當(dāng)自動(dòng)檢測打開時(shí),測試 fixture 監(jiān)聽 zone 事件,并調(diào)用 detectChanges。當(dāng)你的測試代碼直接修改了組件屬性值時(shí),你還是要調(diào)用 fixture.detectChanges 來觸發(fā)數(shù)據(jù)綁定更新。
默認(rèn)值是 false,喜歡對測試行為進(jìn)行精細(xì)控制的測試者一般保持它為 false。

checkNoChanges

運(yùn)行一次變更檢測來確認(rèn)沒有待處理的變化。如果有未處理的變化,它將拋出一個(gè)錯(cuò)誤。

isStable

如果 fixture 當(dāng)前是穩(wěn)定的,則返回 true。如果有異步任務(wù)沒有完成,則返回 false。

whenStable

返回一個(gè)承諾,在 fixture 穩(wěn)定時(shí)解析。
要想在完成了異步活動(dòng)或異步變更檢測之后再繼續(xù)測試,可以對那個(gè)承諾對象進(jìn)行掛鉤。

destroy

觸發(fā)組件的銷毀。

DebugElement

?DebugElement ?提供了對組件的 DOM 的訪問。

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

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

成員

詳情

nativeElement

與瀏覽器中 DOM 元素對應(yīng)(WebWorkers 時(shí),值為 null)。

query

調(diào)用 query(predicate: Predicate<DebugElement>) 會在子樹的任意深度中查找并返回能和謂詞函數(shù)匹配的第一個(gè) DebugElement。

queryAll

調(diào)用 queryAll(predicate: Predicate<DebugElement>) 會在子樹的任意深度中查找能和謂詞函數(shù)匹配的所有 DebugElement。

injector

宿主依賴注入器。比如,根元素的組件實(shí)例注入器。

componentInstance

元素自己的組件實(shí)例(如果有)。

context

為元素提供父級上下文的對象。通常是控制該元素的祖級組件實(shí)例。
當(dāng)一個(gè)元素被 *ngFor 重復(fù),它的上下文為 NgForOf,它的 $implicit 屬性值是該行的實(shí)例值。比如,*ngFor="let hero of heroes" 里的 hero。

children

DebugElement 的直接子元素??梢酝ㄟ^繼續(xù)深入 children 來遍歷這棵樹。

?DebugElement ?還有 ?childNodes?,即 ?DebugNode ?對象列表。?DebugElement ?從 ?DebugNode ?對象衍生,而且通常節(jié)點(diǎn)(node)比元素多。測試者通常忽略普通節(jié)點(diǎn)。

parent

DebugElement 的父級。如果 DebugElement 是根元素,parent 為 null。

name

元素的標(biāo)簽名字,如果它是一個(gè)元素的話。

triggerEventHandler

如果在該元素的 listeners 集合中有相應(yīng)的監(jiān)聽器,就根據(jù)名字觸發(fā)這個(gè)事件。第二個(gè)參數(shù)是該處理器函數(shù)所需的事件對象
如果事件缺乏監(jiān)聽器,或者有其它問題,考慮調(diào)用 nativeElement.dispatchEvent(eventObject)。

listeners

元素的 @Output 屬性以及/或者元素的事件屬性所附帶的回調(diào)函數(shù)。

providerTokens

組件注入器的查詢令牌。包括組件自己的令牌和組件的 providers 元數(shù)據(jù)中列出來的令牌。

source

source 是在源組件模板中查詢這個(gè)元素的處所。

references

與模板本地變量(比如 #foo)關(guān)聯(lián)的詞典對象,關(guān)鍵字與本地變量名字配對。

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

這個(gè)條件方法是任何接受一個(gè) ?DebugElement ?并返回真值的方法。下面的例子查詢所有擁有名為 ?content ?的模塊本地變量的所有 ?DebugElement?:

// Filter for DebugElements with a #content reference
const contentRefs = el.queryAll( de => de.references['content']);

Angular 的 ?By ?類為常用條件方法提供了三個(gè)靜態(tài)方法:

靜態(tài)方法

詳情

By.all

返回所有元素

By.css(selector)

返回符合 CSS 選擇器的元素

By.directive(directive)

返回 Angular 能匹配一個(gè)指令類實(shí)例的所有元素

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


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號