不意外的今天依舊測試 typescript,不過有趣的是可以來測試 observable,雖然課程有 async function 由於前幾篇有提過,今天就不再重複。
學習課程名稱如下:
我們來看看,原始元件 typescript 檔案
Subscriptions And Observables 元件,調用 ApiService 的 getData 用 subscribe 取值,將其值傳到另一個函式
ApiService 使用到 Subject 可以從外部訂閱
接著來看看,對應的 Spec 檔案,configureTestingModule 一樣取代成測試用的元件
beforeEach(waitForAsync(() => {
configureTestingModule({
declarations: [
TestingSubscriptionsAndObservablesComponent
],
}).compileComponents();
}));
在測試 Spec 第一個案例都是先檢查「元件是否存在」,因為前幾篇實做過這邊就不再贅述。
(1) 使用 spyOn 取得元件服務 handleData,字串需與元件函式同名
(2) 接著使用 BehaviorSubject ,手動 emmit 一個新值 line 4
。Subject 可以接受外部訂閱,也可以訂閱其他的 Observable,而 BehaviorSubject 會在每次被外部訂閱時,emmit 目前已收到的最新值。
(3) 繼續準備測資,將 ApiService 注入到測試案例,以便後續的使用,line 5
(4) 利用 asObservable() 將 getDataSubject 轉換成單純 Observable,在將值 emmit 給 returnValue 使用
(5) 因為在一開始 line 6
已經在 ngOnInit 調用 getData 狀態已經改變,所以在呼叫一次 init 重新訂閱 getData 函式
(6) 用 next
手動觸發新值輸出 line 10
(7) 第一個 it 檢查 'handleData' 是否至少被呼叫一次,並且帶著5的參數; 第二個 it 檢查 handleData 拿到的回傳值 5 有沒有和前述設定的測資 3 相同。
it('should call handleData when recieving new data', () => {
//Assign
const spy = spyOn(component,'handleData');
const getDataSubject = new BehaviorSubject<number>(3);
const apiService = TestBed.inject(ApiService);
spyOn(apiService,'getData').and.returnValue(getDataSubject.asObservable());
//Act
component.ngOnInit(); // Subscribe again since the function was just changed.
getDataSubject.next(5); // Emit a new value
//Assert
expect(spy).toHaveBeenCalledWith(5);
});
it('should set the data when recieving new data', () => {
//Assign
const apiService = TestBed.inject(ApiService);
const subject = new BehaviorSubject<number>(3);
spyOn(apiService,'getData').and.returnValue(subject.asObservable());
//Act
component.ngOnInit(); // Subscribe again
subject.next(5); // Emit a new value
//Assert
expect(component.data).toEqual(5);
});
要用文字翻譯測試程式碼,實在有點抽象,而且對 Rxjs 熟悉度還不夠深,所以在理解測試 Observable 這段又繼續補充知識,不過對於 UT 測試 Observable 有基本的認識。
下一篇要來測試沒看過的 Route 和 Local Storage