React測試框架之enzyme

簡介

Enzyme是由Airbnb開源的一個React的JavaScript測試工具,使React組件的輸出更加容易extrapolate 。Enzyme的API和jQuery操做DOM同樣靈活易用,由於它使用的是cheerio庫來解析虛擬DOM,而cheerio的目標則是作服務器端的jQuery。Enzyme兼容大多數斷言庫和測試框架,如chai、mocha、jasmine等。html

安裝與配置

使用enzyme以前,須要在項目中安裝enzyme依賴,安裝的命令以下:node

npm install --save-dev enzyme
複製代碼

因爲React 項目須要依賴React的一些東西,因此請確保如下模塊已經安裝。react

npm install --save react react-dom babel-preset-react
複製代碼

要完成渲染測試,除了enzyme以外,還須要Enzyme Adapter庫的支持,因爲React 版本的不一樣,Enzyme Adapter的版本也不同。適配器和React的對應表以下:npm

Enzyme Adapter Package React semver compatibility
enzyme-adapter-react-16 ^16.0.0
enzyme-adapter-react-15 ^15.5.0
enzyme-adapter-react-14.4 ^15.5.0
enzyme-adapter-react-14 ^0.14.0
enzyme-adapter-react-13 ^0.13.0

enzyme支持三種方式的渲染: shallow:淺渲染,是對官方的Shallow Renderer的封裝。將組件渲染成虛擬DOM對象,只會渲染第一層,子組件將不會被渲染出來,於是效率很是高。不須要DOM環境, 並可使用jQuery的方式訪問組件的信息; render:靜態渲染,它將React組件渲染成靜態的HTML字符串,而後使用Cheerio這個庫解析這段字符串,並返回一個Cheerio的實例對象,能夠用來分析組件的html結構。 mount:徹底渲染,它將組件渲染加載成一個真實的DOM節點,用來測試DOM API的交互和組件的生命週期,用到了jsdom來模擬瀏覽器環境。json

經常使用函數

enzyme中有幾個比較核心的函數須要注意,以下:數組

  • simulate(event, mock):用來模擬事件觸發,event爲事件名稱,mock爲一個event object;
  • instance():返回測試組件的實例;
  • find(selector):根據選擇器查找節點,selector能夠是CSS中的選擇器,也能夠是組件的構造函數,以及組件的display name等;
  • at(index):返回一個渲染過的對象;
  • get(index):返回一個react node,要測試它,須要從新渲染;
  • contains(nodeOrNodes):當前對象是否包含參數重點 node,參數類型爲react對象或對象數組;
  • text():返回當前組件的文本內容;
  • html(): 返回當前組件的HTML代碼形式;
  • props():返回根組件的全部屬性;
  • prop(key):返回根組件的指定屬性;
  • state():返回根組件的狀態;
  • setState(nextState):設置根組件的狀態;
  • setProps(nextProps):設置根組件的屬性;

使用

爲了方便講解Enzyme測試的用法,咱們首先新建一個enzyme.js的測試文件。代碼以下:瀏覽器

import React from 'react'

const Example=(props)=>{
    return (<div>
        <button>{props.text}</button>
    </div>)
}
export default Example
複製代碼

淺渲染shallow

前面說過,Shallow Rendering用於將一個組件渲染成虛擬DOM對象,可是隻渲染第一層,不渲染全部子組件,因此處理速度很是快。而且它不須要DOM環境,由於根本沒有加載進DOM。bash

爲了進行淺渲染shallow測試,咱們新建一個名爲enzyme.test.js的測試文件。服務器

import React from 'react'
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import Example from '../enzyme'

const {shallow}=Enzyme

Enzyme.configure({ adapter: new Adapter() })

describe('Enzyme shallow', function () {
    it('Example component', function () {
        const name='按鈕名'
        let app = shallow(<Example text={name} />)
       let btnName=app.find('button').text();
       console.log('button Name:'+btnName)
    })
})
複製代碼

執行yarn test命令,會看到以下的運行結果: babel

在這裏插入圖片描述

爲了不每一個測試文件都這麼寫,咱們能夠再test目錄下新建一個配置文件enzyme_config.test.js。文件內容以下:

import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({
    adapter: new Adapter(),
});

export default Enzyme;
複製代碼

而後,在test目錄下新建一個文件setup.js:

import jsdom from 'jsdom';
const { JSDOM } = jsdom;

if (typeof document === 'undefined') {
    const dom=new JSDOM('<!doctype html><html><head></head><body></body></html>');
    global.window =dom.window;
    global.document = global.window.document;
    global.navigator = global.window.navigator;
}
複製代碼

修改咱們的package.json中的測試腳本爲以下配置:

"scripts": {
    "test": "mocha --require babel-core/register --require ./test/setup.js"
  }
複製代碼

如今,咱們的shallow測試代碼能夠改成:

import React from 'react'
import Enzyme from './enzyme.config';
import Example from '../enzyme'

const {shallow}=Enzyme

describe('Enzyme shallow', function () {
    it('Example component', function () {
        const name='按鈕名'
        let app = shallow(<Example text={name} />)
        let btnName= app.find('button').text()
        console.log('button Name:'+btnName)
    })
})
複製代碼

徹底渲染mount

mount渲染用於將React組件加載爲真實DOM節點。然而,真實DOM須要一個瀏覽器環境,爲了解決這個問題,咱們能夠用到jsdom,也就是說咱們能夠用jsdom模擬一個瀏覽器環境去加載真實的DOM節點。 首先,使用下面的命令安裝jsdom模擬瀏覽器環境,安裝命令以下:

npm install --save-dev jsdom
複製代碼

而後咱們添加一個徹底渲染的測試代碼:

import React from 'react'
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import Example from '../src/example'

const {shallow,mount}=Enzyme

Enzyme.configure({ adapter: new Adapter() })

describe('Enzyme mount的DOM渲染(Full DOM Rendering)中', function () {
  it('Example組件中按鈕的名字爲子組件Sub中span的值', function () {
    const name='按鈕名'
    let app = mount(<Example text={name} />)

    const buttonObj=app.find('button')
    const spanObj=app.find('span')

    console.info(`查找到button的個數:${buttonObj.length}`)
    console.info(`查找到span的個數:${spanObj.length}`)

   buttonObj.text(),spanObj.text()
  })
})

複製代碼

說明,因爲完成測試的配置好像有點問題,因此此處的代碼有些跑不通。

靜態渲染render

render靜態渲染,主要用於將React組件渲染成靜態的HTML字符串,而後使用Cheerio這個庫解析這段字符串,並返回一個Cheerio的實例對象,能夠用來分析組件的html結構。針對前面的enzyme.js文件,咱們的靜態渲染測試的代碼以下:

import React from 'react'
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import Example from '../enzyme'

const {shallow,mount,render}=Enzyme

Enzyme.configure({ adapter: new Adapter() })

describe('Enzyme render test', function () {
    it('Example render', function () {
        const name='按鈕名'
        let app = render(<Example text={name} />)

        const buttonObj=app.find('button')
        const spanObj=app.find('span')

        console.info(`查找到button的個數:${buttonObj.length}`)
        console.info(`查找到span的個數:${spanObj.length}`)

        buttonObj.text(),spanObj.text()
    })
})
複製代碼

執行上面的代碼,測試結果以下:

在這裏插入圖片描述

對比

爲了對比這三大測試框架,咱們能夠對比看一下:

describe('shallow vs render vs mount', function () {
    it('測試 shallow 500次', () => {
        for (let i = 0; i < 500; i++) {
            const app = shallow(<Example/>)
            app.find('button').text()
        }
    })

    it('測試render500次', () => {
        for (let i = 0; i < 500; i++) {
            const app = render(<Example/>)
            app.find('button').text()
        }
    })

    it('測試mount500次', () => {
        for (let i = 0; i < 500; i++) {
            const app = mount(<Example/>)
            app.find('button').text()
        }
    })
})
複製代碼

運行結果以下圖:

在這裏插入圖片描述

如上圖,shallow是最快的,這是由於shallow的侷限性,只渲染第一層,不渲染全部子組件。事實證實,render的效率是mount的兩倍。 那麼問題來了,mount存在的價值是什麼?固然是有價值的,shallow和mount由於都是dom對象的緣故,因此都是能夠模擬交互的。

相關文章
相關標籤/搜索