Jest 是 Facebook 開發的一個測試框架,它集成了測試執行器、斷言庫、spy、mock、snapshot和測試覆蓋率報告等功能。React項目自己也是使用Jest進行單測的,所以它們倆的契合度至關高。css
Enzyme 是由 airbnb 開發的React單測工具。它擴展了React的TestUtils並經過支持相似jQuery的find語法能夠很方便的對render出來的結果作各類斷言。html
Jest+Enzyme是目前比較流行的React項目單測組合。node
npm install --save-dev jest jest-cli enzyme
在package.json中添加jest命令,並指定配置文件.jest.jsreact
scripts: { "test": "jest --config .jest.js" }
在項目根目錄新建配置文件.jest.js,以下git
module.exports = { setupFiles: [ './tests/setup.js', // 測試啓動文件 ], testURL: 'http://localhost', // 測試環境URL testEnvironment: 'jsdom', // 測試環境 moduleFileExtensions: ['js', 'jsx'], // 單元測試文件檢測後綴名 testPathIgnorePatterns: ['/node_modules/'], moduleNameMapper: { // mock模塊 "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/tests/__mocks__/fileMock.js", "\\.(css|less)$": "<rootDir>/tests/__mocks__/cssMock.js" }, transformIgnorePatterns: [ // 不轉化es6的文件夾匹配 'node_modules\/[^/]+?\/(?!(es|node_modules)\/)', // Ignore modules without es dir ] };
由配置文件的testEnvironment能夠看到,測試環境使用的是jsdom
,jsdom 爲許多 WEB標準的 JavaScript 實現,它主要是爲了在服務器端模擬足夠的Web瀏覽器子集,以便進行自動化測試。程序員
因爲jest默認不支持es6和jsx語法,咱們須要經過babel對其進行轉化,在項目根目錄新建.babelrc文件:es6
{ "env": { "test": { "presets": ["es2015", "react", "stage-2"] } } }
對於測試環境來講,一些模塊咱們不須要進行處理,好比圖片模塊、樣式模塊,咱們須要把這些模塊mock掉,經過moduleNameMapper配置,把指定文件後綴的模塊使用自定義文件mock掉,如圖片模塊,咱們新建/tests/__mock__/fileMock.js文件:github
module.exports = {}
導出一個空對象來mock圖片文件。web
對於一些css、less等文件,可能涉及到一些css-module的內容,可能引入的模塊裏包含了css中:export導出的內容,如classPrefix,這個時候若是導出空對象可能會影響測試的結果,咱們這裏針對項目導出寫死的內容,/tests/__mock__/cssMock.js以下:chrome
module.exports = { prefix: "test", switchPrefix: "test-switch", btnPrefix: "test-btn", inputPrefix: "test-input" }
這個時候當咱們導入css模塊時候,咱們能夠模擬到css-module的功能,使用s.prefix取到test字符串。
接下來新建啓動文件/tests/setup.js
import { JSDOM } from 'jsdom'; // fixed jsdom miss if (typeof window !== 'undefined') { const documentHTML = '<!doctype html><html><body</body></html>'; global.document = new JSDOM(documentHTML); // 模擬 document 對象 global.window = document.parentWindow; // 模擬 window 對象 } global.requestAnimationFrame = global.requestAnimationFrame || function (cb) { // 處理兼容 添加 requestAnimationFrame 動畫函數 return setTimeout(cb, 0); }; const Enzyme = require('enzyme'); const Adapter = require('enzyme-adapter-react-16'); Enzyme.configure({ adapter: new Adapter() }); // 爲 enzyme 添加適配器,針對不一樣的react版本使用不一樣的適配器
默認狀況下,jest會檢測__tests__
文件下的全部.js
和.jsx
後綴以及項目中.test.js
和.spec.js
後綴(包括jsx)的文件,以標記這些文件爲單元測試文件。
以antd爲例,新建一個button.test.js文件:
import React, { Component } from 'react'; import { render, mount } from 'enzyme'; import { Button } from 'antd'; describe('Button', () => { it('按鈕測試', () => { const wrapper = render( <Button>測試</Button> ); expect(wrapper).toMatchSnapshot(); }); it('測試加載中', () => { class DefaultButton extends Component { state = { loading: false, }; enterLoading = () => { this.setState({ loading: true }); } render() { return <Button loading={this.state.loading} onClick={this.enterLoading}>Button</Button>; } } const wrapper = mount( <DefaultButton /> ); wrapper.simulate('click'); expect(wrapper.find('.ant-btn-loading').length).toBe(1); }); })
toMatchSnapshot
方法會測試兩次單測渲染的結果是否一致。
執行命令 npm run test
,結果以下:
enzyme提供了三種渲染方式,render
、mount
、shallow
,分別存在如下區別:
render
採用的是第三方庫Cheerio的渲染,渲染結果是普通的html結構,對於snapshot使用render比較合適。shallow
和mount
對組件的渲染結果不是html的dom樹,而是react樹,若是你chrome裝了react devtool插件,他的渲染結果就是react devtool tab下查看的組件結構,而render函數的結果是element tab下查看的結果。shallow
和mount
的結果是個被封裝的ReactWrapper
,能夠進行多種操做,譬如find()、parents()、children()
等選擇器進行元素查找;state()
、props()
進行數據查找,setState()、setprops()操做數據;simulate()模擬事件觸發。shallow
只渲染當前組件,只能能對當前組件作斷言;mount
會渲染當前組件以及全部子組件,對全部子組件也能夠作上述操做。通常交互測試都會關心到子組件,我使用的都是mount。可是mount耗時更長,內存啥的也都佔用的更多,若是不必操做和斷言子組件,可使用shallow。enzyme還提供了simulate()
接口模擬事件,實際上simulate是經過觸發事件綁定函數,來模擬事件的觸發。觸發事件後,去判斷props上特定函數是否被調用,傳參是否正確;組件狀態是否發生預料之中的修改;某個dom節點是否存在是否符合指望。
自 WebStorm 2017.3以後的版本(以前幾個版本也有,可是不知道怎麼試都不行),WebStorm也提供了jest的單元測試環境,下面結合咱們前面的項目進行配置:
打開debug配置窗口,在defaults裏面找到jest,修改jest的全局配置,選擇jest配置文件,以下:
選擇完後點擊肯定,而後找到對應的單元測試文件,點擊左邊的運行鍵,以下:
選擇 Debug 便可在對應的位置打斷點進行調試。
單元測試的目的是爲了檢測一段代碼在特定條件下某個特定的函數行爲,對程序員來講,單元測試仍是很必要的存在,由於測試人員不會徹底把bug測出來,這個時候爲了更好的發現bug,咱們就須要單元測試來保證測試的全面性。
上面項目 github傳送門。