React 是一款广受欢迎的前端开发框架,而单元测试也是进行前端开发时不可或缺的一环。在 React 中,我们可以使用 Enzyme 这个单元测试工具来帮助我们进行组件的测试。本文将介绍 Enzyme 的使用及解决方案,并附有示例代码。
Enzyme 简介
Enzyme 是由 Airbnb 开发的 React 组件测试工具,它的主要作用是帮助我们在本地开发环境中测试 React 组件的行为和输出。Enzyme 提供了一系列的 API,能够让我们轻松地模拟 React 组件的环境,以及操作组件的 Props 和 State。
Enzyme 的 API 分为三个部分:
shallow: 浅层渲染,只会渲染组件的直接子组件,父组件不会渲染。在进行 UI 测试时使用,因为只需要测试当前组件的行为和输出,无需考虑其子组件的影响。
mount:完整渲染,模拟组件在真实浏览器环境中运行的情况。使用 mount 来测试的时候需要注意,需要考虑其子组件的影响,因为子组件也会被渲染,可能会影响测试结果。
render: 静态 HTML 渲染,将组件渲染成 HTML,不需要浏览器环境,适用于测试组件的 HTML 结构。
Enzyme 安装
要使用 Enzyme 进行测试,首先需要安装它。Enzyme 可以通过 NPM 进行安装,输入以下命令进行安装:
npm install enzyme enzyme-adapter-react-16 react-test-renderer --save-dev
- enzyme:Enzyme 库
- enzyme-adapter-react-16 :React 16 适配器
- react-test-renderer:React 测试工具
安装完成后,需要在 test 文件中引入 Enzyme 以及适配器:
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });Enzyme 使用
在已经安装并配置好 Enzyme 后,我们可以通过一个实际的示例来学习如何使用它。
考虑以下组件:
// www.javascriptcn.com code example
import React, { Component } from 'react';
class Example extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
count: this.state.count + 1,
});
}
render() {
const count = this.state.count;
return (
<div>
<p>{count}</p>
<button onClick={this.handleClick}>点击</button>
</div>
);
}
}
export default Example;这是一个简单的计数器组件,有一个 count 的 state 和一个 button 可以点击累加 count.
我们来看看如何使用 Enzyme 进行测试。
shallow 渲染测试
我们首先进行 Enzyme 渲染测试,这里展示一个 shallow 渲染测试,即只渲染当前组件,不渲染子组件。
// www.javascriptcn.com code example
import React from 'react';
import Enzyme, { shallow } from 'enzyme'; //引入需要的测试模块
import Adapter from 'enzyme-adapter-react-16';
import Example from './Example'; //引入测试的组件
Enzyme.configure({ adapter: new Adapter() }); //配置 Enzyme
describe('Example组件测试', () => {
it('初始化count状态应该为0', () => {
const wrapper = shallow(<Example />); //shallow 渲染 Example 组件
expect(wrapper.state('count')).toEqual(0); //断言count 初始化状态
});
it('点击按钮后,count 状态应该加一', () => {
const wrapper = shallow(<Example />); //shallow 渲染 Example 组件
const btn = wrapper.find('button'); //查找一个 button
btn.simulate('click'); //模拟点击按钮,触发 handleClick 函数
expect(wrapper.state('count')).toEqual(1); //断言count状态加一
});
});mount 渲染测试
接下来,我们来进行完全渲染测试,即对父组件和子组件进行渲染。mount 渲染测试需要考虑子组件对测试结果的影响,因为子组件也会被渲染,可能会影响测试结果。
我们在组件中添加一个子组件,测试完全渲染后,子组件是否被渲染。
// www.javascriptcn.com code example
import React from 'react';
import Enzyme, { mount } from 'enzyme'; //引入需要的测试模块
import Adapter from 'enzyme-adapter-react-16';
import Example from './Example'; //引入测试的组件
import SubComp from './SubComp'; //引入子组件(假设存在子组件)
Enzyme.configure({ adapter: new Adapter() }); //配置 Enzyme
describe('Example组件测试', () => {
it('初始化count状态应该为0', () => {
const wrapper = mount(<Example />); //完全渲染 Example 组件(包含子组件)
expect(wrapper.state('count')).toEqual(0); //断言 count 初始化状态
expect(wrapper.find(SubComp).length).toEqual(1); //断言子组件 SubComp 被渲染
});
it('点击按钮后,count 状态应该加一', () => {
const wrapper = mount(<Example />); //完全渲染 Example 组件(包含子组件)
const btn = wrapper.find('button'); //查找一个 button
btn.simulate('click'); //模拟点击按钮,触发 handleClick 函数
expect(wrapper.state('count')).toEqual(1); //断言 count 状态加一
expect(wrapper.find(SubComp).length).toEqual(1); //断言子组件 SubComp 被渲染
});
});render 静态 HTML 测试
最后,我们来进行静态 HTML 测试,即将组件渲染成 HTML。这种测试方法主要用于测试组件输出的 HTML 结构,不需要考虑组件行为和交互。
// www.javascriptcn.com code example
import React from 'react';
import { render } from 'enzyme';
import Example from './Example';
it('Example组件的HTML渲染结果测试', () => {
const wrapper = render(<Example />);
expect(wrapper.find('p').text()).toEqual('0');
expect(wrapper.find('button').text()).toEqual('点击');
});Enzyme 解决方案
在使用 Enzyme 进行测试时,可能会遇到一些问题,我们需要通过一些解决方案来解决这些问题。
React Hook
当使用 Hook(useEffect,useState,useCallback 等)时,可以使用 mount 方法进行测试。
注意点:
对于使用
React.memo进行优化的组件,mount 全部重新渲染,所以建议使用shallow或render方法进行测试。如果在编写 useEffect 时使用了空数组([])的方式实现了 componentDidMount 时候的调用,建议使用
shallow方法进行测试,因为在 mount 中,会进行componentDidMount 执行以及 useEffect 回调的函数调用。
Ref
在测试 ref 时,可以使用 mount 方法,然后通过 .instance() 方法获取 ref 对象。
举例:
it('test ref',()=>{
const wrapper = mount(<Ref/>);
const instance = wrapper.instance();
expect(instance.input.current.value).toEqual('test');
})async await
当需要测试异步代码时,我们需要使用 async/await。
it('async event test ', async () => {
const wrapper = mount(<Async/>);
wrapper.find('button').simulate('click');
await flushPromise(wrapper);
expect(wrapper.state('count')).toEqual(1);
})其中 flushPromise 函数的实现如下:
const flushPromise = wrapper => new Promise(resolve => setTimeout(resolve).then(() => wrapper.update()) );
结尾
本文介绍了 Enzyme 的使用及解决方案,并附有代码示例。在使用 Enzyme 进行测试时,需要我们根据实际情况选择不同的 API 进行测试并注意一些细节问题,使得测试结果更加准确和可靠。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d813b6a941bf7134e6b89d