基于Jest+Enzyme的React單元測(cè)試

本文為實(shí)踐的產(chǎn)物,總結(jié)從搭建到使用過(guò)程中遇到的問(wèn)題,初學(xué)者可以參考。

  • Jest 和 Enzyme 的基本介紹
  • 測(cè)試環(huán)境搭建
  • 測(cè)試腳本編寫(xiě)
  • 運(yùn)行并調(diào)試
  • 匹配器使用
  • 測(cè)試異步代碼
  • 遇到的問(wèn)題
  • 參考資料

Jest、Enzyme介紹
Jest是Facebook發(fā)布的一個(gè)開(kāi)源的、基于Jasmine框架的JavaScript單元測(cè)試工具,支持?jǐn)嘌浴⒎抡妗⒖煺諟y(cè)試、測(cè)試覆蓋率報(bào)告等。

Enzyme獲得React 官方的推薦,Airbnb開(kāi)源的React測(cè)試類庫(kù)Enzyme提供了一套簡(jiǎn)介強(qiáng)大的API,并通過(guò)jQuery風(fēng)格的方式進(jìn)行DOM處理,開(kāi)發(fā)體檢十分友好。

強(qiáng)烈推薦閱讀使用jest+enzyme進(jìn)行react項(xiàng)目測(cè)試 - 介紹篇

測(cè)試環(huán)境搭建
在開(kāi)發(fā)React應(yīng)用的基礎(chǔ)上,需要安裝Jest、Enzyme以及對(duì)應(yīng)的babel-jest。
使用 yarn 安裝 Jest︰
yarn add --dev jest enzyme babel-jest

npm
npm install --save-dev jest enzyme babel-jest

將下面的配置部分添加到package.json 里面:

{
  "scripts": {
    "test": "jest"
  } 
"jest": {
    "moduleFileExtensions": [
      "js",
      "jsx"
    ],
    "moduleNameMapper": {
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
      ".*\\.(css|less|scss)$": "<rootDir>/__mocks__/styleMock.js"
    },
    "transform": {
      "^.+\\.js$": "babel-jest"
    }
  },
}
  • moduleFileExtensions:代表支持加載的文件名,與Webpack中的resolve.extensions類似
  • moduleNameMapper:代表需要被Mock的資源名稱。如果需要Mock靜態(tài)資源(如less、scss等),需要配置Mock的路徑<rootDir>/mocks/xxMock.js
  • transform:用于編譯 ES6/ES7 語(yǔ)法,需配合 babel-jest使用
    這三個(gè)是常用的配置,更多 Jest 配置見(jiàn)官方文檔:Jest Configuration

然后,創(chuàng)建xx.test.js的文件,寫(xiě)實(shí)際的測(cè)試邏輯
最后,運(yùn)行yarn test

測(cè)試腳本編寫(xiě)
強(qiáng)烈推薦閱讀使用jest+enzyme進(jìn)行react項(xiàng)目測(cè)試 - 測(cè)試手法篇
測(cè)試用例寫(xiě)法總結(jié)

  • 組件UI測(cè)試用snapshot
    snapshot可以測(cè)試到組件的渲染結(jié)果是否符合預(yù)期,預(yù)期就是指你上一次錄入保存的結(jié)果,toMatchSnapshot方法會(huì)去幫你對(duì)比這次將要生成的結(jié)構(gòu)與上次的區(qū)別
    需要注意的是一個(gè)足夠健壯的測(cè)試應(yīng)該覆蓋到所有的渲染請(qǐng)況,也就是如果你的組件根據(jù)props傳入的參數(shù)渲染結(jié)果可能不同,這樣的情況必須寫(xiě)多個(gè)測(cè)試案例都覆蓋到。

  • DOM交互測(cè)試用Jest+Enzyme
    enzyme有3種渲染方式:render、mount、shallow
    render、mount、shallow的區(qū)別
    render采用的是第三方庫(kù)Cheerio的渲染,渲染結(jié)果是普通的html結(jié)構(gòu),對(duì)于snapshot使用render比較合適。

    shallow和mount對(duì)組件的渲染結(jié)果不是html的dom樹(shù),而是react樹(shù),如果你chrome裝了react devtool插件,他的渲染結(jié)果就是react devtool tab下查看的組件結(jié)構(gòu),而render函數(shù)的結(jié)果是element tab下查看的結(jié)果。

    這些只是渲染結(jié)果上的差別,更大的差別是shallow和mount的結(jié)果是個(gè)被封裝的ReactWrapper,可以進(jìn)行多種操作,譬如find()、parents()、children()等選擇器進(jìn)行元素查找;state()、props()進(jìn)行數(shù)據(jù)查找,setState()、setprops()操作數(shù)據(jù);simulate()模擬事件觸發(fā)。

    shallow只渲染當(dāng)前組件,只能能對(duì)當(dāng)前組件做斷言;mount會(huì)渲染當(dāng)前組件以及所有子組件,對(duì)所有子組件也可以做上述操作。一般交互測(cè)試都會(huì)關(guān)心到子組件,我使用的都是mount。但是mount耗時(shí)更長(zhǎng),內(nèi)存啥的也都占用的更多,如果沒(méi)必要操作和斷言子組件,可以使用shallow。

  • 交互測(cè)試
    主要利用simulate()接口模擬事件,實(shí)際上simulate是通過(guò)觸發(fā)事件綁定函數(shù),來(lái)模擬事件的觸發(fā)。觸發(fā)事件后,去判斷props上特定函數(shù)是否被調(diào)用,傳參是否正確;組件狀態(tài)是否發(fā)生預(yù)料之中的修改;某個(gè)dom節(jié)點(diǎn)是否存在是否符合期望。

  • mock請(qǐng)求
    需要mock掉真正的http請(qǐng)求,模擬返回值。不用擔(dān)心不準(zhǔn)確,你只用保證請(qǐng)求時(shí)的參數(shù)符合期望就好,mock的返回值按預(yù)期編寫(xiě)就好,置于這些請(qǐng)求是否真的能返回這些結(jié)果,是接口測(cè)試改干的活。

運(yùn)行并調(diào)試
在運(yùn)行測(cè)試腳本過(guò)程,Jest 的錯(cuò)誤提示信息友好,通過(guò)錯(cuò)誤信息一般都能找到問(wèn)題的所在。 同時(shí) Jest 還提供了生成測(cè)試覆蓋率報(bào)告的命令,只需要在package.json 里配置{ "scripts": { "test": "jest --coverage " } 即可生成。會(huì)在終端中顯示如下報(bào)告:

image.png

而且還會(huì)在項(xiàng)目中生成 coverage 文件夾,非常方便。

匹配器使用
推薦閱讀:
前端測(cè)試框架Jest系列教程 -- Matchers(匹配器)
Javascript單元測(cè)試工具-Jest 學(xué)習(xí)筆記(一)

測(cè)試異步代碼
推薦閱讀:
Javascript單元測(cè)試工具-Jest 學(xué)習(xí)筆記(一)
學(xué)習(xí)Jest——語(yǔ)法篇

遇到的問(wèn)題
Image.onload不能被監(jiān)聽(tīng)到
解決辦法參考:https://zhuanlan.zhihu.com/p/37329102
我采用了自己 mock Image 構(gòu)造函數(shù)方案

最后,在寫(xiě)測(cè)試用例過(guò)程中,不知道用什么匹配器,可以來(lái)Jest官網(wǎng)搜羅一圈https://jestjs.io/docs/zh-Hans/expect
不知道使用Enzyme什么API時(shí),也來(lái)Enzyme搜羅一圈http://airbnb.io/enzyme/docs/api/
總能找到你想要的~

參考資料
https://zhuanlan.zhihu.com/p/26625269

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評(píng)論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,348評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,083評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,706評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,442評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,802評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,983評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,542評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,287評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,486評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,710評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,116評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,412評(píng)論 1 294
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,224評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,462評(píng)論 2 378

推薦閱讀更多精彩內(nèi)容