在 Angular 應(yīng)用中那伐,路由對整個應(yīng)用的用戶體驗踏施,起著非常重要的作用。因此罕邀,對路由進行單元測試读规,可以確保應(yīng)用的正確和高效運行。
路由的單元測試工作燃少,主要包括以下三個方面:
- 測試導(dǎo)航地址是否正確
- 測試路由參數(shù)是否正確
- 測試加載組件是否正確
測試導(dǎo)航地址
在 Angular 應(yīng)用中束亏,通過在 a
元素上添加 routerLink 指令,實現(xiàn)路由功能阵具。
在測試前碍遍,我們需要建立一個指令的 stub
定铜,避免做大量的工作去建立完整的 routerLink
.
import { Directive, Input } from "@angular/core”;
@Directive({
selector: '[routerLink]’
})
export class RouterLinkDirectiveStub {
@Input('routerLink') linkParams: any;
}
在這里,selector
必須匹配 routerLink
指令怕敬,才能正常工作揣炕。我們會使用 routerLink
綁定,實現(xiàn)真實的 routerLink
指令的行為东跪。這樣畸陡,routerLink
指令的 linkParams
屬性會把導(dǎo)航地址傳遞給 stub
.
現(xiàn)在可以編寫測試:
it('should set up routerLink directives', () => {
const linkDe = fixture.debugElement.queryAll(By.directive(RouterLinkDirectiveStub));
const links = linkDe.map(de => de.injector.get(RouterLinkDirectiveStub));
expect(links.length).toBe(2);
expect(links[0].linkParams).toEqual('home’);
expect(links[1].linkParams).toEqual(['heroes', 1]);
});
it('should get the id parameter', () => {
expect(component.heroId).toBe(1);
});
在測試用例中,我們使用 By
工具類的 directive
方法虽填,指定查詢元件的類型:組件或指令丁恭。 debugElement
屬性的 queryAll
方法,返回了所有查詢到的 routerLink
指令斋日。然后牲览,就可以對指令的數(shù)量,鏈接參數(shù)進行測試恶守。
測試路由參數(shù)
- 調(diào)整提供導(dǎo)航的組件:
@Component({
selector: 'app-menu’,
templateUrl: './menu.component.html’,
styleUrls: ['./menu.component.css’]
})
export class MenuComponent implements OnInit {
bookId: number;
constructor(private route: ActivatedRoute) { }
ngOnInit(): void {
this.route.paramMap.subscribe(params => this.bookId = + params.get('id’));
}
}
在初始化函數(shù)中第献,對 paramMap
方法進行訂閱,獲得參數(shù) id
對值兔港。
- 創(chuàng)建一個
stub
庸毫,模擬paramMap
方法的行為:
export class ActivatedRouteStub {
private subject = new ReplaySubject<ParamMap>();
constructor(initialParams?: Params) {
this.setParamMap(initialParams);
}
readonly paramMap = this.subject.asObservable();
setParamMap(params?: Params) {
this.subject.next(convertToParamMap(params));
}
}
在這里,可以使用 constructor
構(gòu)造函數(shù)或 setParamMap
設(shè)置路由參數(shù)衫樊。
- 編寫單元測試:
…
beforeEach(() => {
const activatedRoute = new ActivatedRouteStub();
activatedRoute.setParamMap({id: 1});
TestBed.configureTestingModule({
declarations: [
MenuComponent,
RouterLinkDirectiveStub,
RouterOutletComponentStub
],
providers: [
{ provide: ActivatedRoute, useValue: activatedRoute }
],
})
.compileComponents();
});
...
it('should get the id parameter', () => {
expect(component.bookId).toBe(1);
});
首先飒赃,在測試初始化階段,創(chuàng)建了 ActivatedRouteStub
類的一個實例橡伞,并設(shè)置參數(shù) id 的值為 1. 然后盒揉,在配置測試模塊時,把 activatedRoute
作為提供者進行添加兑徘。最后刚盈,我們驗證組件的屬性是否正確接收了來自路由參數(shù)的值。
測試加載組件
Angular 為我們提供了一個測試真實路由功能的類 RouterTestingModule
挂脑,可以定義我們在測試時需要的路由:
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([{
path: 'heroes/:id’,
component: MenuComponent
}])
],
declarations: [MenuComponent]
});
通過使用這個方法藕漱,不僅可以測試路由的導(dǎo)航地址和路由參數(shù),也可以測試是否正確加載組件崭闲。
為了測試加載組件肋联,需要創(chuàng)建一個組件的 stub
,提供 router-outlet
刁俭,作為組件加載的占位符橄仍。
@Component({
selector: 'router-outlet’,
template: ‘'
})
export class RouterOutletComponentStub { }
最后,在配置測試模塊的時候,可以為 schemas
屬性添加 NO_ERRORS_SCHEMA
侮繁。這樣虑粥,就不必再去創(chuàng)建一個目標組件,Angular 會忽略任何在模板中不能識別的組件宪哩。