在Angular測(cè)試中使用spy的教程詳解
簡(jiǎn)介
Jasmine spy 用于跟蹤或存根函數(shù)或方法。spy 是一種檢查函數(shù)是否被調(diào)用或提供自定義返回值的方法。我們可以使用spy 來測(cè)試依賴于服務(wù)的組件,并避免實(shí)際調(diào)用服務(wù)的方法來獲取值。這有助于保持我們的單元測(cè)試專注于測(cè)試組件本身的內(nèi)部而不是其依賴關(guān)系。
在本文中,您將學(xué)習(xí)如何在 Angular 項(xiàng)目中使用 Jasmine spy。
先決條件
要完成本教程,您需要:
- 在本地安裝 Node.js
- 一些關(guān)于設(shè)置 Angular 項(xiàng)目的基礎(chǔ)知識(shí)。
本教程已使用 Node v16.2.0、npm
v7.15.1 和 @angular/core
v12.0.4 進(jìn)行驗(yàn)證。
步驟 1 — 設(shè)置項(xiàng)目
讓我們使用一個(gè)與我們?cè)?Angular 單元測(cè)試介紹中使用的示例非常相似的示例。
首先,使用 @angular/cli
創(chuàng)建一個(gè)新項(xiàng)目:
ng new angular-test-spies-example
然后,切換到新創(chuàng)建的項(xiàng)目目錄:
cd angular-test-spies-example
以前,該應(yīng)用程序使用兩個(gè)按鈕在 0 到 15 之間增加和減少值。
對(duì)于本教程,邏輯將被移動(dòng)到一個(gè)服務(wù)中。這將允許多個(gè)組件訪問相同的中央值。
ng generate service increment-decrement
然后,打開您的代碼編輯器中的 increment-decrement.service.ts
并用以下代碼替換內(nèi)容:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class IncrementDecrementService { value = 0; message!: string; increment() { if (this.value < 15) { this.value += 1; this.message = ''; } else { this.message = 'Maximum reached!'; } } decrement() { if (this.value > 0) { this.value -= 1; this.message = ''; } else { this.message = 'Minimum reached!'; } } }
打開您的代碼編輯器中的 app.component.ts
并用以下代碼替換內(nèi)容:
import { Component } from '@angular/core'; import { IncrementDecrementService } from './increment-decrement.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { constructor(public incrementDecrement: IncrementDecrementService) { } increment() { this.incrementDecrement.increment(); } decrement() { this.incrementDecrement.decrement(); } }
打開您的代碼編輯器中的 app.component.html
并用以下代碼替換內(nèi)容:
<h1>{{ incrementDecrement.value }}</h1> <hr> <button (click)="increment()" class="increment">Increment</button> <button (click)="decrement()" class="decrement">Decrement</button> <p class="message"> {{ incrementDecrement.message }} </p>
接下來,打開您的代碼編輯器中的 app.component.spec.ts
并修改以下代碼行:
import { TestBed, waitForAsync, ComponentFixture } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { DebugElement } from '@angular/core'; import { AppComponent } from './app.component'; import { IncrementDecrementService } from './increment-decrement.service'; describe('AppComponent', () => { let fixture: ComponentFixture<AppComponent>; let debugElement: DebugElement; let incrementDecrementService: IncrementDecrementService; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ declarations: [ AppComponent ], providers: [ IncrementDecrementService ] }).compileComponents(); fixture = TestBed.createComponent(AppComponent); debugElement = fixture.debugElement; incrementDecrementService = debugElement.injector.get(IncrementDecrementService); })); it('should increment in template', () => { debugElement .query(By.css('button.increment')) .triggerEventHandler('click', null); fixture.detectChanges(); const value = debugElement.query(By.css('h1')).nativeElement.innerText; expect(value).toEqual('1'); }); it('should stop at 15 and show maximum message', () => { incrementDecrementService.value = 15; debugElement .query(By.css('button.increment')) .triggerEventHandler('click', null); fixture.detectChanges(); const value = debugElement.query(By.css('h1')).nativeElement.innerText; const message = debugElement.query(By.css('p.message')).nativeElement.innerText; expect(value).toEqual('15'); expect(message).toContain('Maximum'); }); });
請(qǐng)注意,我們可以使用 debugElement.injector.get
獲取對(duì)注入服務(wù)的引用。
以這種方式測(cè)試我們的組件是有效的,但實(shí)際調(diào)用也將被傳遞到服務(wù),并且我們的組件沒有被孤立測(cè)試。接下來,我們將探討如何使用 spy 來檢查方法是否已被調(diào)用或提供存根返回值。
步驟 2 —— 監(jiān)視服務(wù)的方法
以下是如何使用 Jasmine 的 spyOn
函數(shù)調(diào)用一個(gè)服務(wù)方法并測(cè)試它是否被調(diào)用:
import { TestBed, waitForAsync, ComponentFixture } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { DebugElement } from '@angular/core'; import { AppComponent } from './app.component'; import { IncrementDecrementService } from './increment-decrement.service'; describe('AppComponent', () => { let fixture: ComponentFixture<AppComponent>; let debugElement: DebugElement; let incrementDecrementService: IncrementDecrementService; let incrementSpy: any; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ declarations: [ AppComponent ], providers: [ IncrementDecrementService ] }).compileComponents(); fixture = TestBed.createComponent(AppComponent); debugElement = fixture.debugElement; incrementDecrementService = debugElement.injector.get(IncrementDecrementService); incrementSpy = spyOn(incrementDecrementService, 'increment').and.callThrough(); })); it('should call increment on the service', () => { debugElement .query(By.css('button.increment')) .triggerEventHandler('click', null); expect(incrementDecrementService.value).toBe(1); expect(incrementSpy).toHaveBeenCalled(); }); });
spyOn 接受兩個(gè)參數(shù):類實(shí)例(在本例中是我們的服務(wù)實(shí)例)和一個(gè)字符串值,表示要監(jiān)視的方法或函數(shù)的名稱。
在這里,我們還在 spy 上鏈接了 .and.callThrough(),這樣實(shí)際方法仍然會(huì)被調(diào)用。在這種情況下,我們的 spy 只用于判斷方法是否被調(diào)用以及監(jiān)視參數(shù)。
以下是斷言方法被調(diào)用兩次的示例:
expect(incrementSpy).toHaveBeenCalledTimes(2);
以下是斷言方法未被使用 'error'
參數(shù)調(diào)用的示例:
expect(incrementSpy).not.toHaveBeenCalledWith('error');
如果我們想避免實(shí)際調(diào)用服務(wù)上的方法,可以在 spy 上使用 .and.returnValue
。
我們的示例方法不適合這樣做,因?yàn)樗鼈儾环祷厝魏蝺?nèi)容,而是改變內(nèi)部屬性。
讓我們向服務(wù)添加一個(gè)實(shí)際返回值的新方法:
minimumOrMaximumReached() { return !!(this.message && this.message.length); }
我們還向組件添加一個(gè)新方法,模板將使用它來獲取值:
limitReached() { return this.incrementDecrement.minimumOrMaximumReached(); }
然后,我們可以測(cè)試當(dāng)達(dá)到限制時(shí),我們的模板消息是否會(huì)顯示,而無需實(shí)際調(diào)用服務(wù)上的方法:
import { TestBed, waitForAsync, ComponentFixture } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { DebugElement } from '@angular/core'; import { AppComponent } from './app.component'; import { IncrementDecrementService } from './increment-decrement.service'; describe('AppComponent', () => { let fixture: ComponentFixture<AppComponent>; let debugElement: DebugElement; let incrementDecrementService: IncrementDecrementService; let minimumOrMaximumSpy: any; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ declarations: [ AppComponent ], providers: [ IncrementDecrementService ] }).compileComponents(); fixture = TestBed.createComponent(AppComponent); debugElement = fixture.debugElement; incrementDecrementService = debugElement.injector.get(IncrementDecrementService); minimumOrMaximumSpy = spyOn(incrementDecrementService, 'minimumOrMaximumReached').and.returnValue(true); })); it(`should show 'Limit reached' message`, () => { fixture.detectChanges(); const message = debugElement.query(By.css('p.message')).nativeElement.innerText; expect(message).toEqual('Limit reached!'); }); });
結(jié)論
在本文中,您學(xué)習(xí)了如何在 Angular 項(xiàng)目中使用 Jasmine spy。
到此這篇關(guān)于在Angular測(cè)試中使用spy的教程詳解的文章就介紹到這了,更多相關(guān)Angular中使用spy內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
AngularJS基礎(chǔ)學(xué)習(xí)筆記之控制器
在AngularJS中,控制器是一個(gè)Javascript函數(shù)(類型/類),用來增強(qiáng)除了根作用域意外的作用域?qū)嵗?。?dāng)你或者AngularJS本身通過<code>scope.$new</code>倆創(chuàng)建一個(gè)新的子作用域?qū)ο髸r(shí),有一個(gè)選項(xiàng)能讓你將它當(dāng)做參數(shù)傳遞給控制器。2015-05-05Angular 1.x個(gè)人使用的經(jīng)驗(yàn)小結(jié)
這篇文章主要給大家介紹了關(guān)于Angular 1.x個(gè)人使用的一些經(jīng)驗(yàn),屬于一些基礎(chǔ)入門教程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-07-07AngularJS的依賴注入實(shí)例分析(使用module和injector)
這篇文章主要介紹了AngularJS的依賴注入,結(jié)合實(shí)例形式分析了依賴注入的原理及使用module和injector實(shí)現(xiàn)依賴注入的步驟與操作技巧,需要的朋友可以參考下2017-01-01

AngularJS實(shí)現(xiàn)的生成隨機(jī)數(shù)與猜數(shù)字大小功能示例

AngularJS ng-change 指令的詳解及簡(jiǎn)單實(shí)例

AngularJS自定義插件實(shí)現(xiàn)網(wǎng)站用戶引導(dǎo)功能示例