前端單元測試框架梳理

mguy_1發表於2019-05-13

作為一個前端,一開始並不知道單元測試的好處,覺得費時費力,效果也不明顯,直到有個模組因為效能問題進行了一次重構,被折磨得筋疲力盡的時候,才發現單元測試的好處,可以說,有了單元測試,才能面對其他同事寫的或者n年以前的程式碼,放心大膽的對其進行持續的維護甚至重構。

  • 單元測試有別於整合測試,是對最小可測試單元(一般為單個函式或小元件)進行檢查和驗證。功能越簡單越好,單個驗證其他變數影響越少越好,這樣能達到最好的效果。好的單元測試用例可以充當開發文件供後人閱讀。

斷言庫 chai

單元測試的核心就是斷言,通過斷言來判斷程式碼是否達到目的

node內建斷言assert,以下圖為最簡單例子,如果錯誤會丟擲異常

前端單元測試框架梳理

chai這個斷言庫很全很強大,提供了常用的assert should expect斷言關鍵字

前端單元測試框架梳理
各類的用法就不提了,方法比較簡單,一查便知。 assert最簡單,不過目前expect用得比較多,例如expert(xxx).toBe(xxxx) 但是egg官網推薦assert,理由是簡單,不用記一些複雜api。

前端單元測試框架梳理

前端單元測試框架梳理

Mocha

Mocha是老牌的庫,簡單全面易用,目前公司就在用Mocha+chai測試前端資料邏輯,用來測試node,util裡面的函式都可以,測試元件需要搭配其他框架。

Mocha測試的鉤子 Mocha在describe塊之中,提供測試用例的四個鉤子:before()、after()、beforeEach()和afterEach()。 可以用before鉤子提前把測試環境和資料準備好,beforeEach鉤子可以在每個測試用例前準備一個或多個新的物件,防止被前面的用例汙染

describe('測試index.js',()=> {
  before(()=>console.info("在本區塊的所有測試用例之前執行"))
  after(()=>console.info("在本區塊的所有測試用例之後執行"))
  beforeEach(()=>console.info("在本區塊的每個測試用例之前執行"))
  afterEach(()=>console.info("在本區塊的每個測試用例之後執行"))
  describe('測試addNum函式', ()=> {
    it('兩數相加結果為兩個數字的和', ()=> {
      assert.equal(addNum(1,2),3)
    })
  })
})
複製程式碼

最後,Mocha預設每個測試用例最多執行2000毫秒,如果到時沒有得到結果,就報錯, 而且Mocha預設會高亮顯示超過75毫秒的測試用例,可修改

sinon

sinon具有非常有特色的spies, stub, mock三個功能,有興趣的可以嘗試手寫實現。

  • spies的概念

spies => 間諜函式,間諜函式是Sinon最簡單的部分,其它的功能都是建立在spies之上的,spies的主要用途是收集有關函式呼叫的資訊,例如是否呼叫了函式等。spies的實現監聽的基礎上是不會影響函式本身正常呼叫(被監聽的函式的上下文關係不會被影響)。

  • stub的概念

stub完全取代了這個函式,而且擁有spies的所有功能。當使用stub時,函式將不具有原始的功能,而是替換後的函式。

  • mock的概念

mock與stub的功能一樣都是用來替換指定的函式,如果你想替換掉一個物件中的多個方法,這時mock就可以發揮作用了,但是如果僅僅是替換物件中的一個函式,那麼stub更加簡單易用,當我們使用mock的時候應該十分小心,因為大量的替換原有程式碼邏輯,會導致test變的脆弱。

nock或者moxios

用來模擬傳送網路請求,需要替代後臺介面時使用。

Karma

非jsdom,提供真實瀏覽器環境,由於目前各類框架已經比較完善了,現在已經基本被排除在主流框架之外

redux-mock-store

顧名思義,用於模擬 redux 中的 store。由於工作中一直用mobx,這裡不多做介紹了

jasmine

使用與jest類似,以前通常和karma配合,大而全的測試框架(jest)成為主流後,用的少了

jest

jest 是facebook推出的一款測試框架,整合了Mocha,chai,jsdom,sinon等功能。所以剛入門的同學如果想應用直接可以上jest。

react官方腳手架自帶jest,vue-cli3.0中也整合了單元測試框架,選擇的時候會問你選mocha+chai還是jest。

  • 執行命令 jest 後會自動執行專案下所有.test.js和.spec.js這種格式的檔案。jest的配置預設只要在package.json中配置即可,如只測test資料夾下test.jsx檔案
 "jest": {
    "testRegex": "/test/*.test.jsx?$"
 }
複製程式碼
  • 整合expect斷言

  • 非同步處理 對於callback採用done()確保完成測試,對於promise自動處理,遇到reject自動丟擲錯誤,async+await同理

  • Jest 中的 mock , 類似於sinon的 sinon,並且還可以模擬axios的網路請求

  • 快照snapshot 對元件或者資料生成一份快照,每次測試自動深比較,不一致就報錯

  • 可以生成測試覆蓋率報告,只需要在jest命令後加入 --coverage即可

jest --coverage
複製程式碼

enzyme && test-utils

airbnb公司推出的 enzyme ,專門用來測試react元件,相對應vue中也有test-utils包,基本是一樣的功能,也是對元件掛載後進行事件觸發、元素存在等判斷。

這裡以enzyme為例講解,enzyme主要提供三種渲染方式:render、mount、shallow,存在以下區別:

render渲染結果是普通的html結構,shallow和mount對元件的渲染結果是react樹,如果你用過chrome的react devtool外掛,他的渲染結果就是react devtool tab下檢視的元件結構。

shallow和mount的返回結果是個被封裝的ReactWrapper,可以進行多種類似JQ的鏈式操作,譬如find()、parents()、children()等選擇器進行元素查詢;state()、props()進行資料查詢,setState()、setprops()運算元據;simulate()模擬事件觸發。

shallow只渲染當前元件,只對當前元件做斷言,不會產生子元件;mount會渲染當前元件以及所有子元件,對所有子元件也可以做上述操作。一般互動測試都會關心到子元件,我使用的都是mount。但是mount耗時更長,記憶體啥的也都佔用的更多,如果沒必要操作和斷言子元件,一般使用shallow。

總結

單元測試屬於需要投入,但是看不見產出的工作,所以直接選擇最簡潔的框架,節約時間,才是提升kpi的關鍵,現在的框架越來越趨向簡單和人性化,所以如果工作中使用,直接選jest類整合框架就好。

我在的toB傳統軟體服務公司,前端的穩定性更加重要,在一個產品快速迭代期後,單元測試也會逐步進行覆蓋util模組和model層(響應action的資料變化處理),其它則需要看迭代排期,經常重構的基礎公共元件也會排上。每個公司需求不同,如果是上線就撤的專案,可以不用部署測試。考慮引進單元測試前,請靈活考慮成本和收益

相關文章