React組件單元測試

React組件自動化測試

1. 爲何要進行自動化測試

當咱們編寫一個組件的時候,要怎麼保證組件功能能達到預期呢?你可能回答:我能夠人工測試。可是當經歷三四次迭代,當有多人協調開發,當進行重構的時候,如何能快速的驗證組件是否依然正確執行?這正是須要自動化測試的緣由。不管經歷多少次迭代,好的自動化測試都能保證你的組件可以正確執行。javascript

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

通過測試的組件是可靠的,可測的組件的架構是合理的。若是一個組件難如下手編寫測試用例,只能證實這個組件的設計是糟糕的。所以,編寫測試用例的同時,能夠幫助組件開發者發現問題,調整代碼使架構更加合理。java

2. 自動化測試的基礎內容

(1) 自動化測試分類react

按照測試方法分類:黑盒測試和白盒測試segmentfault

黑盒測試也稱功能測試,在測試中,把程序看做一個不能打開的黑盒子,在徹底不考慮程序內部結構和內部特性的狀況下,在程序接口進行測試。用戶對內部邏輯並不可見。react-native

白盒測試又稱結構測試、透明盒測試、邏輯驅動測試或基於代碼的測試。白盒測試是一種測試用例設計方法,盒子指的是被測試的軟件,白盒指的是盒子是可視的,你清楚盒子內部的東西以及裏面是如何運做的。」白盒"法全面瞭解程序內部邏輯結構、對全部邏輯路徑進行測試。bash

(2) 測試金字塔微信

該概念是Mike Cohn 在他的著做《Succeeding with Agile》一書中提出的。架構

測試金字塔中提到的兩件事:app

  • 編寫不一樣粒度的測試
  • 層次越高,你寫的測試應該越少

(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%。

進一步打開詳情查看,原來是有一部分代碼僅有if而沒有else,因此這部分未達到100%是能夠忽略的。

若是十分介意,能夠在if前加入/* istanbul ignore else */。

onChange(e) {
    var val = e.target.value;
    /* istanbul ignore else */
    if (this.props.onChange) {
      this.props.onChange(val);
    }
  }
複製代碼

這樣就能夠達到100%了。

總結

本文上半部分主要闡述了自動化測試的一些基礎知識,下半部分經過一個textinput組件實例,闡述瞭如何編寫有價值的測試用例,達到對組件代碼的全覆蓋。

參考

React 單元測試策略及落地

測試金字塔實戰

前端自動化測試概覽

對 React 組件進行單元測試

Web 前端單元測試到底要怎麼寫

7 architectural attributes of a reliable React component

測試覆蓋(率)到底有什麼用?

做者簡介

南溪,銅板街前端開發工程師,2016年4月加入團隊,目前主要負責資金端交易側 H5項目開發。

本文主要經過具體的案例講述了React組件單元測試的過程,如需獲取更多React相關內容,請掃碼關注 「銅板街科技」 微信公衆號,並在後臺回覆「React」 或者 「react-native」 獲取更多精彩內容。
相關文章
相關標籤/搜索