当前位置: 首页 > 工具软件 > Enzyme > 使用案例 >

React 测试利器之 Enzyme

江正德
2023-12-01

一. Enzyme简述

react测试利器enzyme有三种渲染方式:shallow, mount, render。shallow渲染叫浅渲染,仅仅对当前jsx结构内的顶级组件进行渲染,而不对这些组件的内部子组件进行渲染,因此,它的性能上最快的,大部分情况下,如果不深入组件内部测试,那么可以使用shallow渲染。mount则会进行完整渲染,而且完全依赖DOM API,也就是说mount渲染的结果和浏览器渲染结果说一样的,结合jsdom这个工具,可以对上面提到的有内部子组件实现复杂交互功能的组件进行测试。render也会进行完整渲染,但不依赖DOM API,而是渲染成HTML结构,并利用cheerio实现html节点的选择,它相当于只调用了组件的render方法,得到jsx并转码为html,所以组件的生命周期方法内的逻辑都测试不到,所以render常常只用来测试一些数据(结构)一致性对比的场景。在这里还提到,shallow实际上也测试不到componentDidMount/componentDidUpdate这两个方法内的逻辑。

二. Enzyme 三种渲染方式

shallow

Shallow Rendering(浅渲染)指的是,将一个组件渲染成虚拟DOM对象,但是只渲染第一层,不渲染所有子组件(即忽略父组件内的所有子组件),所以处理速度非常快。它不需要DOM环境,因为根本没有加载进DOM(可以理解为虚拟Dom)。
shallow的函数输入组件,返回组件的浅渲染结果,而返回的结果可以用类似jquery的形式获取组件的信息。

实例请至 React 之 jest 前端自动化测试 的 UI 测试部分实例

常用API:
.find(selector) => ShallowWrapper //找到所有匹配的节点
.findWhere(predicate) => ShallowWrapper //找到所有渲染树下满足函数内判断的节点
.filter(selector) => ShallowWrapper //过滤匹配的节点
.filterWhere(predicate) => ShallowWrapper
.contains(nodeOrNodes) => Boolean
.containsMatchingElement(node) => Boolean
.containsAllMatchingElements(nodes) => Boolean
.containsAllMatchingElements(nodes) => Boolean
.equals(node) => Boolean
.matchesElement(node) => Boolean
.hasClass(className) => Boolean
.is(selector) => Boolean
.isEmpty() => Boolean
.not(selector) => ShallowWrapper
.children() => ShallowWrapper
.childAt(index) => ShallowWrapper
.parents() => ShallowWrapper
.parent() => ShallowWrapper
.closest(selector) => ShallowWrapper
.shallow([options]) => ShallowWrapper
.render() => CheerioWrapper

mount

mount方法用于将React组件加载为真实DOM节点,所以可以测试子组件。然而真实DOM需要一个浏览器环境,为了解决这个问题,我们可以用到jsdom(依赖一个用jsdom模拟的浏览器环境).

下面是jsdom的官方介绍:
jsdom is a pure-JavaScript implementation of many web standards, notably the WHATWG DOM and HTML Standards, for use with Node.js. In general, the goal of the project is to emulate enough of a subset of a web browser to be useful for testing and scraping real-world web applications.
也就是说我们可以用jsdom模拟一个浏览器环境去加载真实的DOM节点。

// Demo Code

// src/initGlobal.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;
}


// __tests__/initglobal.test.js
import React from 'react'
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import Example from '../src/initGlobal'

const {shallow,mount}=Enzyme

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

describe('Enzyme Mount', function () {  
  //测试删除是否起作用 
  it('Delete button',function () {    
    let app = mount(<App/>);      
    let totalLength = app.find("li").length;
    app.find("button.delete").at(0).simulate('click');
    expect(app.find("li").length).to.equal(totalLength-1);  
  });
});

/*
   常用你API:
   .get(index):返回指定位置的子组件的DOM节点
   .at(index):返回指定位置的子组件
   .text():返回当前组件的文本内容
   .html():返回当前组件的HTML代码形式
   .props():返回根组件的所有属性
   .prop(key):返回根组件的指定属性
   .state([key]):返回根组件的状态
*/

render

render静态渲染,主要用于将React组件渲染成静态的HTML字符串,然后使用Cheerio这个库解析这段字符串,并返回一个Cheerio的实例对象,可以用来分析组件的html结构。

// Demo render

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 500次 (116ms)=> render 500次 (421ms) => mount 500次 (984s)

渲染方法是否可以测试子组件是否可以模拟交互性能(测试500次)
shallow116ms
mount421ms
render984ms

Enzyme GitHub 传送门

 类似资料: