深入探討 Angular 整合測試與 Jasmine 的 spyOn()
spyOn()
是整合測試與單元測試的關鍵,本文深入探討 spyOn()
用於整合測試部分。
Version
Angular CLI 1.1.2
Angular 4.2.3
定義
- 驗收測試:以 HTML 與 CSS 的角度測試最後結果,配合真資料測試,與 Angular 無關
- 整合測試:以 Angular 角度測試元件與元件之間的關係,配合假資料測試,與 Angular 有關
- 單元測試:以 class 角度測試,配合假資料測試,與 Angular 無關
最簡單的是單元測試,常常一個
expect()
就可搞定其次是驗收測試,只要會寫 CSS selector 也不難
最難寫的是整合測試,要對相依物件加以假設,並傳入假資料與驗證假資料
測試目的
Q:驗收測試、整合測試與單元測試到底在測什麼?
- 驗收測試:測最終結果
- 整合測試:測之間關係
- 單元測試:測單一結果
整合測試
測試案例:
<h1></h1>
內應該使用getTitle()
函式
1 | it(`should use getTitle() in HTML`, () => { |
在測試 <h1></h1>
內應使用 title
field 時,我們曾經指定 title
為假資料 fake
,並測試 <h1></h1>
內資料是否為 fake
。
同樣的技巧,我們也可以指定 component.getTitle = () => 'fake'
,並測試 <h1></h1>
內資料是否為 fake
。
將相依物件設定為假資料,並測試目前物件是否有相依物件的假資料,為整合測試的基本招式。
SpyOn()
以上方式雖然可行,算土法煉鋼,Jasmine 另外提供更方便的方式:spyOn()
。
Spy 英文為間諜,顧名思義,間諜就是假的,就是幫我們建立假物件、假資料。
若使用 spyOn()
,spyOn()
會對原本的 getTitle()
進行攔胡,HTML 將無法去呼叫原本 TitleComponent.getTitle()
,而改呼叫 Spy.getTitle()
。
spyOn()
另外一個特點,就是對不存在的相依物件進行 spyOn()
時,會測試紅燈
,可藉此驅動出相依物件的單元測試,這也是 ATDD 能 out side in 的關鍵。
callFake()
1 | it(`should use getTitle() in HTML`, () => { |
callFake()
會傳入 arrow function 回傳假資料,用來取代想 spyOn()
的 function。
最後 expect()
一樣測試假資料。
returnValue()
1 | it(`should use getTitle() in HTML`, () => { |
直接使用 returnValue()
回傳假資料,寫法比 callFake()
簡潔。
最後 expect()
一樣測試假資料。
calls.any()
1 | it(`should use getTitle() in HTML`, () => { |
整合測試重點是測試之間的關係,而測試假資料只是一種手段,若能直接測試 getTitle()
是有被呼叫到,會更符合整合測試的精神。
使用 spyOn()
回傳一個物件,在 expect()
內測試 spy.calls.any()
,若該 spyOn()
的 function 有被呼叫到則為 true
。
toHaveBeenCalled()
1 | it(`should use getTitle() in HTML`, () => { |
以整合測試的角度,我們想測試的是之間的關係,也就是重點是有沒有被呼叫到,之前用假資料測試假資料只是一種手段,若 Jasmine 能直接 expect()
不就更理想?
Jasmine 提供了 expect().toHaveBeenCalled()
,若 spyOn()
的 function 被呼叫執行過,就會傳回 true
。
toHaveBeenCalled()
是語意最佳的整合測試寫法,強烈推薦。
SpyOn() 使用時機
- 整合測試:用來對尚未實作的相依物件建立假物件,讓目前的整合測試
紅燈
,驅動出相依物件的單元測試紅燈
。 - 單元測試:用來對已經實作的相依物件建立假物件,讓目前的單元測試
綠燈
。
1
是 ATDD 的理論基礎。
2
是 TDD 的理論基礎。
Conclusion
- Jasmine 的
spyOn()
無法對 field 加以 spy,因此必須使用整合測試的基本技巧:使用假值並測試假值,但 method 可直接spyOn()
,建議直接搭配toHaveBeenCalled()
。 - 大部分人都是在單元測試使用
spyOn()
,將相依物件加以隔離,但事實上在整合測試使用spyOn()
配合toHaveBeenCalled()
,還可以驅動出相依物件的單元測試,這正是 ATDD 由整合測試紅燈
,驅動出單元測試紅燈
的關鍵技術。