Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React不完全测试指南 #7

Open
xchunzhao opened this issue Jul 15, 2019 · 0 comments
Open

React不完全测试指南 #7

xchunzhao opened this issue Jul 15, 2019 · 0 comments

Comments

@xchunzhao
Copy link
Owner

React不完全测试指南

近期团队内部的组件库开始搭建,相应就涉及到组件本身的单元测试。

之前在一些项目中进行了组件以及工具类的单元测试,对于整体测试体系及使用的工具似懂非懂,这篇文章旨在重拾相关内容。

前端测试金字塔

这个名词是一个前端测试结构化的表现。如下:

前端测试金字塔

  • 单元测试(unit test)
    单元测试是针对程序模块来的,项目中的模块小到一个函数或者一个React组件。
  • 快照测试(snapshot test)
    快照测试主要是针对组件的UI进行测试。会将多次测试UI快照进行对比。
  • 冒烟测试(e2e test)
    冒烟测试相当于黑盒测试。只需要根据业务需求,模拟用户的真实场景进行测试。

关于测试的技术选型

根据最近研究的工具来说,个人觉得以下选型是目前我所知的最佳的组合。

测试类别 技术选型
单元测试 Jest + Enzyme
快照测试 Jest
冒烟测试 Jest-puppeteer

覆盖范围

  • 单元测试
分类 测试范围
组件 有条件渲染的 & 有交互 & 有逻辑组件
公共模块 工具类 & 其他公用模块
  • 快照测试

    快照测试需要覆盖到:

    • Page组件
    • 纯展示的公用UI组件
  • e2e测试

    • 核心业务

UI测试(snapshot test)

snapshot可以测试到组件的渲染结果是否符合预期,预期就是指你上一次录入保存的结果,toMatchSnapshot方法会去帮你对比这次将要生成的结构与上次的区别。

snapshot的测试案例形如调用这个组件,传入依赖的props。例如Antd的ToolTip组件:

import { Tooltip } from 'antd';
import { render } from 'enzyme';
import toJson from 'enzyme-to-json';

describe('FileUploadInput render', () => {

  it('basic use', () => {
    const wrapper = render(
      <Tooltip title="prompt text">
        <span>Tooltip will show when mouse enter.</span>
      </Tooltip>
    );
    expect(toJson(wrapper)).toMatchSnapshot();
  })

  it('use arrowPointAtCenter', () => {
    const wrapper = render(
      <div>
        <Tooltip placement="topLeft" title="Prompt Text">
          <Button>Align edge / 边缘对齐</Button>
        </Tooltip>
        <Tooltip placement="topLeft" title="Prompt Text" arrowPointAtCenter>
          <Button>Arrow points to center / 箭头指向中心</Button>
        </Tooltip>
      </div>
    );
    expect(toJson(wrapper)).toMatchSnapshot();
  })

  it('use placement',() => {
    const wrapper = render(<div>
      <div style={{ marginLeft: 60 }}>
        <Tooltip placement="topLeft" title={text}>
          <a href="#">TL</a>
        </Tooltip>
        <Tooltip placement="top" title={text}>
          <a href="#">Top</a>
        </Tooltip>
        <Tooltip placement="topRight" title={text}>
          <a href="#">TR</a>
        </Tooltip>
      </div>
      <div style={{ width: 60, float: 'left' }}>
        <Tooltip placement="leftTop" title={text}>
          <a href="#">LT</a>
        </Tooltip>
        <Tooltip placement="left" title={text}>
          <a href="#">Left</a>
        </Tooltip>
        <Tooltip placement="leftBottom" title={text}>
          <a href="#">LB</a>
        </Tooltip>
      </div>
      <div style={{ width: 60, marginLeft: 270 }}>
        <Tooltip placement="rightTop" title={text}>
          <a href="#">RT</a>
        </Tooltip>
        <Tooltip placement="right" title={text}>
          <a href="#">Right</a>
        </Tooltip>
        <Tooltip placement="rightBottom" title={text}>
          <a href="#">RB</a>
        </Tooltip>
      </div>
      <div style={{ marginLeft: 60, clear: 'both' }}>
        <Tooltip placement="bottomLeft" title={text}>
          <a href="#">BL</a>
        </Tooltip>
        <Tooltip placement="bottom" title={text}>
          <a href="#">Bottom</a>
        </Tooltip>
        <Tooltip placement="bottomRight" title={text}>
          <a href="#">BR</a>
        </Tooltip>
      </div>
    </div>)
    expect(toJson(wrapper)).toMatchSnapshot();
  })
})

交互测试

enzyme有rendermountshallow三种渲染方式,先了解三者区别

rendermountshallow区别:
1、render渲染结果是普通的html结构,对于snapshot使用render比较合适。

2、shallow和mount对组件的渲染结果不是html的dom树,而是react树,如果你chrome装了react devtool插件,他的渲染结果就是react devtool tab下查看的组件结构,而render函数的结果是element tab下查看的结果。

3、这些只是渲染结果上的差别,更大的差别是shallow和mount的结果是个被封装的ReactWrapper,可以进行多种操作,譬如find()、parents()、children()等选择器进行元素查找;state()、props()进行数据查找,setState()、setprops()操作数据;simulate()模拟事件触发。

4、shallow只渲染当前组件,只能能对当前组件做断言;mount会渲染当前组件以及所有子组件,对所有子组件也可以做上述操作。一般交互测试都会关心到子组件,我使用的都是mount。但是mount耗时更长,内存啥的也都占用的更多,如果没必要操作和断言子组件,可以使用shallow。

从测试角度反思应用设计

[好测试]的前提是有[好代码]。因此需要思考如何让应用更好设计。

  • 单一职责。一个组件只做一件事,降低复杂度。
  • 良好的复用。例如复用逻辑的同时,也复用了测试用例。
  • 保证最小可用,再逐渐增加功能。Done is better than perfect
  • 原本不利于测试的代码还是需要修改的,并不能为了原代码稳定不变,在测试时不敢动原代码。譬如函数不纯,没有返回值等。

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant