React单元测试——十八般兵器齐上阵,环境构建篇

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('往页面插入一段带有span标签的组件', () => {

let instance = ReactTestUtils.renderIntoDocument(

<Alert>

<span>Message</span>

</Alert>

);

assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'span'));

});

});

如上述代码所示,我们假设往<Alert>组件中放置了一个<span>标签并渲染到页面上(这里使用了 react/lib/ReactTestUtils 是我们下篇文章要介绍的东西)

于是我们断言页面上通过此形式所挂载上去的 Alert 组件里肯定有一个 <span> 标签,如果找不到这个 <span> 标签则意味着该单元测试失败。

现在我们似乎基本完成了全部的配置,执行 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 目录下的全部组件进行简单的单元测试~ 更多有趣的配置或工具我们在后续的文章再做介绍。

最后依旧提醒一下,本文的示例可以从我的仓库上下载到,有兴趣的读者可以下载了自行研究~ 共勉~

以上是 React单元测试——十八般兵器齐上阵,环境构建篇 的全部内容, 来源链接: utcz.com/z/382097.html

回到顶部