React组件单元测试

栏目: 编程工具 · 发布时间: 5年前

内容简介:当我们编写一个组件的时候,要怎么保证组件功能能达到预期呢?你可能回答:我可以人工测试。但是当经历三四次迭代,当有多人协调开发,当进行重构的时候,如何能快速的验证组件是否依然正确执行?这正是需要自动化测试的原因。无论经历多少次迭代,好的自动化测试都能保证你的组件能够正确执行。A component that is untestable or hard to test is most likely badly designed.经过测试的组件是可靠的,可测的组件的架构是合理的。如果一个组件难以下手编写测试用例,

当我们编写一个组件的时候,要怎么保证组件功能能达到预期呢?你可能回答:我可以人工测试。但是当经历三四次迭代,当有多人协调开发,当进行重构的时候,如何能快速的验证组件是否依然正确执行?这正是需要自动化测试的原因。无论经历多少次迭代,好的自动化测试都能保证你的组件能够正确执行。

A component that is untestable or hard to test is most likely badly designed.

经过测试的组件是可靠的,可测的组件的架构是合理的。如果一个组件难以下手编写测试用例,只能证明这个组件的设计是糟糕的。因此,编写测试用例的同时,可以帮助组件开发者发现问题,调整代码使架构更加合理。

React组件单元测试

2. 自动化测试的基础内容

(1) 自动化测试分类

按照测试方法分类:黑盒测试和白盒测试

React组件单元测试

黑盒测试也称功能测试,在测试中,把程序看作一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,在程序接口进行测试。用户对内部逻辑并不可见。

白盒测试又称结构测试、透明盒测试、逻辑驱动测试或基于代码的测试。白盒测试是一种测试用例设计方法,盒子指的是被测试的软件,白盒指的是盒子是可视的,你清楚盒子内部的东西以及里面是如何运作的。”白盒"法全面了解程序内部逻辑结构、对所有逻辑路径进行测试。

(2) 测试金字塔

该概念是Mike Cohn 在他的著作《Succeeding with Agile》一书中提出的。

React组件单元测试

测试金字塔中提到的两件事:

  • 编写不同粒度的测试
  • 层次越高,你写的测试应该越少

(3) 单元测试

指对软件中的最小可测试单元进行检查和验证。单元测试作为测试金字塔最底层,粒度最小,测试速度最快,属于白盒测试。

大多数单元测试包括四个主体:测试套件describe、测试用例it、判定条件expect、断言结果toEqual。

(4) 测试覆盖率

传统的测试覆盖方法常见的有以下几种:

  • 函数覆盖(Function Coverage)
  • 语句覆盖(Statement Coverage)
  • 决策覆盖(Decision Coverage)
  • 条件覆盖(Condition Coverage

3. 前端自动化单元测试工具

Jest

Jest是一个轻量级的JavaScript测试框架,可以应用于Babel, TypeScript, Node, React, Angular, Vue等多种技术栈。

const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
复制代码

Enzyme

翻译为“溶解酶”,作为单元测试渗透于代码各个细节。一般使用 Enzyme 中的 mount 或 shallow 方法,将目标组件转化为一个 ReactWrapper对象,并在测试中调用其各种方法:

import React from 'react';
import { expect } from 'chai';
import { render } from 'enzyme';

import Foo from './Foo';

describe('<Foo />', () => {
  it('renders three `.foo-bar`s', () => {
    const wrapper = render(<Foo />);
    expect(wrapper.find('.foo-bar')).to.have.lengthOf(3);
  });

  it('renders the title', () => {
    const wrapper = render(<Foo title="unique" />);
    expect(wrapper.text()).to.contain('unique');
  });
});
复制代码

4. 编写有价值的React组件单元测试用例

React组件分为四种:

  • 展示型业务组件
  • 容器型业务组件
  • 通用 UI 组件
  • 功能型组件

根据业务场景,本文主要针对功能性组件进行阐述。

功能型组件,指的是跟业务无关的另一类组件:它是功能型的,更像是底层支撑着业务组件运作的基础组件,比如文本框组件、按钮组件等。功能性组件,更注重逻辑性,UI比较没有那么偏重。功能性组件一般包括JS跟CSS两部分内容,CSS部分不作为测试的重点。

功能性组件必须测试的三部分:

  • Props传入;
  • 组件分支渲染逻辑;
  • 事件调用和参数传递。

以上三部分测过后,将会达到较高的测试覆盖率。

本文以Karma+Webpack+Mocha+Chai+Sion+istanbul-instrumenter-loader解决方案作为示例演示如何覆盖以上功能性组件测试的三部分。

首先建立一个简单的Input组件,包含label跟input两个标签,可以定义label跟input的值。

import React from 'react';
import PropTypes from 'prop-types';

export default class TextInput extends React.Component {
  static propTypes = {
    label: PropTypes.string,
    defaultValue: PropTypes.string,
    onChange: PropTypes.func
  }

  static defaultProps = {
    label: '',
    defaultValue: ''
  }

  onChange(e) {
    var val = e.target.value;

    if (this.props.onChange) {
      this.props.onChange(val);
    }
  }


  render() {
    const {label, defaultValue, onChange} = this.props;
    return (
      <div>
        {
          label ? (<label>{label}</label>) : null
        }
        <input defaultValue={this.props.defaultValue} onChange={this.onChange.bind(this)} ></input>
      </div>
    )
  }
}

复制代码

首先,测试Props是否正确传入。

it('Validate attributes of the TextInput', () => {
  const props = {
    label: '测试',
    defaultValue: '测试值'
  }
  const wrapper = mount(<TextInput {...props}/>);
  expect(wrapper.find('label').text()).to.equal('测试');
  expect(wrapper.find('input').prop('defaultValue')).to.equal('测试值');
});
复制代码

其次,测组件分支渲染。

it('Can not render label When label is null', () => {
    const wrapper = mount(<TextInput />);
    expect(wrapper.find('label').length).to.be.empty;
  });
  it('Render label When label is not null', () => {
    const wrapper = mount(<TextInput label='up'/>);
    expect(wrapper.find('label').length).not.to.be.empty;
  });
复制代码

最后,测事件调用。

it('Validate onChange event of the TextInput', () => {
    var temp = '';
    const props = {
      onChange: function(value) {
        temp = value;
      }
    }
    const wrapper = mount(<TextInput {...props} value='测试值'/>);
    var input = wrapper.find('input');
    input.simulate('change', { target: { value: 'Changed' } });
    expect(temp).to.equal('Changed');
  });
复制代码

最后,跑一遍所有的测试用例,均是通过的。然后看下测试覆盖率,分支覆盖率为75%。

React组件单元测试

进一步打开详情查看,原来是有一部分代码仅有if而没有else,所以这部分未达到100%是可以忽略的。

React组件单元测试

如果十分介意,可以在if前加入/* istanbul ignore else */。

onChange(e) {
    var val = e.target.value;
    /* istanbul ignore else  */
    if (this.props.onChange) {
      this.props.onChange(val);
    }
  }
复制代码

这样就可以达到100%了。

React组件单元测试

总结

本文上半部分主要阐述了自动化测试的一些基础知识,下半部分通过一个textinput组件实例,阐述了如何编写有价值的测试用例,达到对组件代码的全覆盖。


以上所述就是小编给大家介绍的《React组件单元测试》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Sass and Compass in Action

Sass and Compass in Action

Wynn Netherland、Nathan Weizenbaum、Chris Eppstein、Brandon Mathis / Manning Publications / 2013-8-2 / USD 44.99

Written by Sass and Compass creators * Complete Sass language reference * Covers prominent Compass community plug-ins * Innovative approach to creating stylesheets Cascading Style Sheets paint the we......一起来看看 《Sass and Compass in Action》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具