最近在進行angular單元測試在組件初始化渲染方面的測試,使用的是RxJS提供的彈珠測試來模擬http請求延遲。segmentfault
可是在某些編輯組件中,ngOnInit方法中使用了router來獲取路由參數。在單元測試中,組件不會接收真的路由參數,所以並無接收到測試數據,初始化時,渲染的組件是空數據。dom
本文的目的,是經過手動發送路由參數,來使組件成功獲取測試數據。ide
本文使用的技術基於:angularu在單元測試中如何模擬HTTP請求延遲單元測試
在未出現問題的狀況下,當咱們爲服務層設置好測試樁、在測試文件中模擬好返回值以後,啓動測試以後,組件會正常渲染,而且會填入模擬返回的隨機數據。
若是在斷言非空的語句Assert.isDefined後面加入console.log,控制檯能夠輸出字符串。測試
以下:this
然而,在後來測試的這幾個組件中,按照示例代碼寫完、測試以後,渲染的組件並無模擬數據,而是空組件。
雖然測試也能經過,但經過是由於斷言的代碼根本沒有執行,代碼中加入console.log,控制檯沒有輸出。以下:spa
儘管在這種狀況下,單元測試也能經過,但事實上,因爲根本沒有接收到返回值,咱們沒法驗證服務層的返回值是否正確,這種作法對項目來講,是不負責任的,這增大了生產環境出錯的風險。
3d
先上組件的ngOnInit初始化代碼:code
ngOnInit() { this.getEditCollege(); } /** * 獲取要編輯的學院 */ public getEditCollege() { // 發起訂閱,獲取路由參數,得到參數後執行回調 this.route.params.subscribe((params: {id: number}) => { console.log("subscribe"); this.collegeService.getCollegeById(params.id).subscribe((data) => { Assert.isDefined(data.id, 'id'); Assert.isDefined(data.name, 'name'); Assert.isDefined(data.code, 'code'); Assert.isDefined(data.number, 'number'); console.log("college->edit"); this.initForm(data); }); }); }
經過概括髮現,全部出錯的組件都有用route獲取路由參數的過程:發起訂閱,當結果返回時執行回調方法,向服務層獲取對象。component
用打斷點的方式得出結論,route發起的訂閱根本沒有返回,所以後面的回調方法也就沒有執行。
由於route是經過路由的變化,來獲取參數路由參數的,但在單元測試中,路由並不會發生變化。
因此須要用一個假的ActiveRouteStub來代替真的ActiveRoute完成單元測試。
/** * ActiveRouteStub * 路由功能服務樁 */ import { Observable, Subject } from 'rxjs'; export class ActivatedRouteStub { paramsSubject = new Subject<any>(); params: Observable<any>; parent: any; snapshot = { paramMap: { get: () => { return 0; } } }; constructor() { this.params = this.paramsSubject.asObservable(); } }
而後從Provider引入(也能夠引入到單元測試專用的輔助模塊中,例如ServiceTestingModule):
providers: [ {provide: ActivatedRoute, useClass: ActivatedRouteStub} ]
接下來經過代碼,收到改變路,傳入和組件接收的類型相對應的參數(示例組件中使用ID):
it('should create', fakeAsync(() => { // 字段斷言,調用getCollegeById expect(component).toBeTruthy(); // 嘗試獲取真的,實際上獲取的假的 const route = TestBed.get(ActivatedRoute) as ActivatedRouteStub; // 發送路由參數,參數爲要編輯的對象的ID route.paramsSubject.next({id: randomNumber()}); }));
這樣,由於route發起的訂閱有了返回值,回調方法被執行,因此被測組件就能得到測試數據。
只有當測試數據真真切切的被填入組件中,咱們才能判定這個組件的初始化確實是正常的。
單元測試中,咱們嚐嚐使用RxJS提供的彈珠測試來模擬http請求延遲,因爲route須要檢測路由變化來獲取參數,而單元測試中組件的路由不會發生變化,所以會形成訂閱沒法返回的狀況,進而致使測試時的組件渲染不正常。
解決辦法就是使用ActiveRouteStub代替ActiveRoute完成測試,手動設置路由變化,以便後面的代碼正常執行,使得被測組件能夠獲取到隨機的測試數據,進而成功渲染。