前端自動化測試(Jest+Enzyme+Antd+React)

前言

本文主要是介紹基於React+Ant Design(如下用Antd表示Ant Design)的項目,在對於本身封裝的,或者基於Antd封裝的公共組件的自動化測試技術的選型和實踐。html

背景

當前前端項目愈來愈大,業務邏輯日益繁雜,協同開發的同事也愈來愈多,迭代頻繁,許多頁面有一些類似的功能,會複用一些組件,這些組件被剝離出來,通常放在component文件夾下,你們共同維護,這時會出現一些常見問題:前端

  • 保證當前組件的質量,即當前業務的正常使用
  • 在新需求下,舊的組件若是能知足新需求50%以上的功能,應當升級舊組件知足新需求,同時兼容舊業務
  • 除該組件Owner以外第二人,在修改組件的過程當中,避免由於對代碼的不熟悉,改出BUG
  • 一個組件多個頁面複用,修改後的測試迴歸任務重

技術選型

目前前端總體的測試框架較爲經常使用的有:react

Jest

源自Facebook,Jest 的一個理念是提供一套完整集成的 「零配置」 測試體驗。app

  • 包含單元測試運行器、斷言庫、Mock庫
  • 內置代碼覆蓋率報告
  • 能夠與Typescript一同使用
  • 零配置,開箱即用

Mocha

僅僅是測試運行器,雖然靈活,但須要本身配置不少東西。框架

React項目測試選型

  • react-addons-test-utils:官方API,有些晦澀
  • Enzyme:源自Airbnb,封裝了React官方測試API,類Jquery風格簡潔的API, 使得Dom操做變得十分友好

綜合目前市面上的輪子,咱們技術選型爲Jest+Enzymedom

實踐

例子是一個基於Antd二次封裝的單選年的日期選擇器,以下演示:函數

圖片描述

代碼結構以下性能

圖片描述

其中測試相關的文件,在__test__中,後綴名爲xxx.test.js的文件,在運行測試時會自動執行,__snapshots__爲自動生成的頁面快照。單元測試

這裏能夠首先簡單的看一下,Jest+Enzyme的基本語法:測試

Jest的API更多着力於定義測試、斷言、mock庫

定義測試:

  • describe: 定義一個測試套件(test suite)
  • it: 定義一個測試(test)
  • beforeEach: 定義一個回調函數在每一個測試以前執行
  • expect: 執行一個斷言
  • jest.fn(): 創造一個mock函數

一些用於斷言的方法:

  • toEqual: 驗證兩個值是否相同
  • toBe: 驗證兩個值是否 === 徹底相等
  • toHaveLength:驗證長度
  • toBeDefined: 驗證一個值是否被定義
  • toContain: 驗證一個list中是否包含某一項
  • toBeCalled: 驗證一個mock函數是否被調用
  • toBeCalledWith: 驗證一個mock函數是否被傳入指定的參數被調用

一些用於mock的方法:

  • mockImplementation: 提供mock函數的執行
  • mockReturnValue: mock函數被調用返回一個值

Enzyme的API更多着重於渲染react組件和從dom樹種檢索指定的節點

下面是三種渲染組件的方法:

  • shallow: 會渲染至虛擬dom,不會返回真實的dom節點,大幅提高測試性能
  • mount: 實現Full Rendering 好比說當咱們須要對DOM API交互或者你須要測試組件的整個生命週期的時候,須要使用這個方法。
  • render: 渲染出最終的html,而後利用這個html結構來進行分析處理

一些被渲染的組件檢索節點的方法:

  • find: 經過匹配選擇器來檢索節點
  • some: 當至少有一個節點匹配選擇器是返回true
  • first: 返回集合的第一個節點
  • at: 返回集合的第n個節點
  • html: 獲取節點的HTML結構
  • text: 獲取節點的文本

一些用於組件交互的方法:

  • simulate: 模擬一個事件
  • setProps: 設置props
  • setState: 設置state
  • props(key): 用於檢索組件的props
  • state(key): 用於檢索組件的state

具體的寫法,index.test.js文件內容以下:

import React, { PureComponent } from 'react';
import { mount, ReactWrapper, render } from 'enzyme';
import YearPicker from '..';

import moment from 'moment';

class YearPickerDemo extends React.Component {
  state = {
    cleared: false,
    value: moment().format('YYYY'),
  };

  render() {
    return (
      <YearPicker
        showTime
        format="YYYY"
        onChange={this.onChange}
        defaultValue={moment('2015/01/01', 'YYYY')}
      />
    );
  }
}

describe('DatePicker', () => {
  it('default value', () => {
    const wrapper = mount(<YearPickerDemo/>);
    expect(wrapper.find('.ant-calendar-picker-input').getDOMNode().value).toBe('2015');
  });

  it('clear value', () => {
    const wrapper = mount(<YearPickerDemo/>);
    wrapper.find('.ant-calendar-picker-clear').hostNodes().simulate('click');
    expect(wrapper.find('.ant-calendar-picker-input').getDOMNode().value).toBe('');
  });

  it('set value in calendar', () => {
    const wrapper = mount(<YearPickerDemo/>);
    wrapper.find('.ant-calendar-picker-input').simulate('click');
    const triggerWrapper = mount(wrapper.find('Trigger').instance().getComponent());
    triggerWrapper.find('[title="2018"]').simulate('click');
    expect(wrapper.find('.ant-calendar-picker-input').getDOMNode().value).toBe('2018');
  });
});

這裏定義了3個測試內容

  • 測試默認值,即檢查輸入框的值是否爲默認值
  • 測試清除按鈕是否可用,經過模擬點擊清除按鈕,測試是否能按照預期清除輸入框內填充的默認值
  • 測試設置值,點擊輸入框,彈出選擇框,選擇值,檢查輸入框中的值是否爲選擇的值
相關文章
相關標籤/搜索