React單元測試——十八般兵器齊上陣,環境構建篇


一個完整、優秀的項目往往離不開單元測試的環節,就 github 上的主流前端項目而言,基本都有相應的單元測試模塊。

就 React 的項目來說,一套完整的單元測試能在在后續迭代更新中回歸錯誤時候給與警示,但鑒於 React 本身的特殊性,我們又常常將其與 webpack 等工具相結合,其單元測試的部署相比常規的項目要折騰的多。

本文將作為 React 單元測試系列的開篇,和大家一同逐步構建其單元測試的環境。

你可以在我的倉庫下載到本文的示例。

文件組織和配置

1. 目錄結構

我們在項目根目錄下新建 src 和 test 文件夾,前者用於存放我們編寫的各 React 組件模塊,后者則用於存放對應單元測試模塊。

接着我們需要一個最本質的 package.json 文件,來描述項目的信息跟依賴模塊,在根目錄執行

npm init

然后分部輸入相關信息(你也可以先一路回車,后續再修改),即可自動生成 package.json。

接着我們先通過 npm 安裝 React 所需的兩個模塊—— react 及 react-dom:

npm install --save-dev react react-dom

這里順便說一聲,React 在 v0.14 開始把 react 模塊拆分成了上述的兩個包,其中 react 模塊 中包含 React.createElement、React.createClass 等API,react-dom 模塊中則包含 ReactDOM.render 等API(更具體的可以戳這里了解)

安裝完成后根目錄會生成存放各 npm 模塊的文件夾 node_modules,我們此刻看到的目錄結構是這樣的,簡簡單單:

2. webpack 配置

我們打算隨主流以ES6的形式來書寫腳本模塊,同時新版的 React 也已經把 JSX 的轉換權移交給 babel 之類的工具,所以我們打算以 webpack 的形式來配置加載器跟打包。

如果你還不了解 webpack,請移步我的這篇入門文章

先通過 npm 安裝 webpack(后續模塊的安裝方式不再贅述):

npm install --save-dev webpack

我們要搭建一個極其簡單的測試環境,所以暫時只需用到一個很簡單的webpack配置,所以咱直接在根目錄下新建一個 webpack.config.js:

var webpack = require('webpack');

module.exports = {
    entry: undefined,
    output: {
        pathinfo: true
    },
    module: {
        //加載器配置
        loaders: [
            { test: /\.js$/, loader: 'babel-loader' }
        ]
    }
};

注意我們打算對所有 .js 文件配置一個 babel-loader 來轉換 JSX 跟 ES6,所以記得通過 npm 安裝上 babel-loader。

3. karma 配置

一個好的測試工具能大大提升你的工作效率,而作為Angular團隊出品的 karma 是出眾的、最受歡迎的一款測試工具,它有如下特點:

1. cli 運行,webstorm下配合完美 
2. 良好支持 mocha、jasmine 等測試框架 
3. 支持多瀏覽器的測試 
4. 生態好,插件多 
5. 集成監控解放雙手,文件變化時自動啟測,類似gulp的watch功能

要留意的是 karma 的安裝最好是以全局的形式來安裝,這樣才能確保正常使用 karma 的cli功能(我們后續將以 karma XXX 的形式來執行測試)

npm install karma -g

接着我們在根目錄下新建 karma.conf.js 配置文件:

var isCI = process.env.CONTINUOUS_INTEGRATION === 'true';
var webpackConfig = require('./webpack.config.js');
module.exports = function(config) {
    config.set({

        basePath: '',

        files: [
            'test/*.js'
        ],

        preprocessors: {
            'test/*.js': ['webpack']
        },

        webpack: webpackConfig,

        webpackMiddleware: {
            noInfo: true
        },

        port: 9876,

        colors: true,

        autoWatch: true,

        singleRun: isCI
    });
};

其中 isCI 變量用於判斷當前系統環境是否已默認支持持續集成(通過環境變量CONTINUOUS_INTEGRATION判斷,具體CI的變量名或值是什么得依據具體情況來定,譬如 vuejs 中使用的是CI_PULL_REQUEST),若沒開啟CI則將 singleRun 設為false。

另外我們在 preprocessors 做了定義,要求執行 test 目錄下的腳本時先通過 webpack 預處理(轉JSX、ES6),並在 webpack 配置項設定其配置為我們之前建立的 webpack.config.js 。

我們打算使用 mocha 來作為單元測試的框架(當然你也可以使用 jasmine),然后使用 phantomjs 來作為測試瀏覽器引擎。

所以先通過 npm 包安裝好這倆個模塊的 karma 插件:

npm install --save-dev karma-mocha karma-phantomjs-launcher

然后我們進一步配置 karma.conf.js:

var isCI = process.env.CONTINUOUS_INTEGRATION === 'true';
var webpackConfig = require('./webpack.config.js');
module.exports = function(config) {
    config.set({

        basePath: '',

        frameworks: [
            'mocha',  'phantomjs'
        ],

        files: [
            'test/*.js'
        ],

        preprocessors: {
            'test/*.js': ['webpack']
        },

        webpack: webpackConfig,

        webpackMiddleware: {
            noInfo: true
        },

        port: 9876,

        colors: true,

        autoWatch: true,

        browsers: ['PhantomJS', 'PhantomJS_custom'],

        customLaunchers: {  //自定義瀏覽器啟動器
            'PhantomJS_custom': {
                base: 'PhantomJS',
                options: {
                    windowName: 'my-window',
                    settings: {
                        webSecurityEnabled: false
                    }
                },
                flags: ['--load-images=true'],
                debug: true
            }
        },

        phantomjsLauncher: {
            // 資源(比如測試模塊)出錯時依舊保持phantom不退出
            exitOnResourceError: true
        },

        singleRun: isCI
    });
};

到了這一步,我們先假裝配置都已經折騰完畢了(其實還沒有),下面是新增測試模塊

4. 創建測試模塊

現在 src 目錄下還沒有任何 React 組件,我們創建一個 Alert.js:

import React from 'react';

const Alert = React.createClass({
    render() {
        return (
            <div {...this.props}>
                {this.props.children}
            </div>
        );
    }
});

export default Alert;

接着在 test 目錄下新增一個 Alert.js 文件,用於對上述的 src/Alert.js 組件進行簡單的單元測試:

import React from 'react';
import ReactTestUtils from 'react/lib/ReactTestUtils';
import Alert from '../src/Alert';

describe('Alert', () => {
    it('往頁面插入一段帶有strong標簽的組件', () => {
        let instance = ReactTestUtils.renderIntoDocument(
            <Alert>
                <strong>Message</strong>
            </Alert>
        );
        assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'strong'));
    });
});

如上述代碼所示,我們假設往<Alert>組件中放置了一個<strong>標簽並渲染到頁面上(這里使用了 react/lib/ReactTestUtils 是我們下篇文章要介紹的東西)

於是我們斷言頁面上通過此形式所掛載上去的 Alert 組件里肯定有一個 <strong> 標簽,如果找不到這個 <strong> 標簽則意味着該單元測試失敗。

現在我們似乎基本完成了全部的配置,執行 karma 啟動單元測試看一看:

karma start --browsers PhantomJS_custom

會發現報錯了:

這是 phantomJS 的一個坑導致的—— phantomJS 不支持 Function.prototype.bind ,詳情可見此issue

解決方法也簡單,把 karma-phantomjs 替換為 karma-phantomjs-shim 即可。

通過 npm 安裝好 karma-phantomjs-shim 后我們修改 karma.conf.js 里的 frameworks 配置項:

        frameworks: [
            'mocha', 'phantomjs-shim'
        ],

然后重新執行 karma,會發現繼續妥妥地報錯:

這是因為 karma 最終是將單元測試運行於一個客戶端瀏覽器中的,而不是node里,而我們的測試模塊又沒有 require('assert') 的引用,客戶端自然取不到assert對象了。

解決方法是使用 karma-chai,通過 npm 安裝后進一步修改 karma.conf.js 里的 frameworks 配置項,加上 chai 插件:

        frameworks: [
            'mocha',  'chai',  'phantomjs-shim'
        ],

然后再執行 karma:

666的~ 到此為止我們的全部配置都折騰完畢。在后續可以使用此方案對 src 目錄下的全部組件進行簡單的單元測試~ 更多有趣的配置或工具我們在后續的文章再做介紹。

最后依舊提醒一下,本文的示例可以從我的倉庫上下載到,有興趣的讀者可以下載了自行研究~ 共勉~

donate


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM