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

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

单元测试React的更多相关文章

  1. 【前端单元测试入门02】react的单元测试之Enzyme

    React项目的单元测试 React的组件结构和JSX语法,对上一章的内容来讲进行测试显得很勉强. React官方已经提供了一个测试工具库:react-dom/test-utils 只是用起来不够方便 ...

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

    一个完整.优秀的项目往往离不开单元测试的环节,就 github 上的主流前端项目而言,基本都有相应的单元测试模块. 就 React 的项目来说,一套完整的单元测试能在在后续迭代更新中回归错误时候给与警 ...

  3. antd-pro1.0使用jest对react组件进行单元测试

    前言 基于React+Ant Design(以下用Antd表示)的项目,在对于自己封装的,或者基于Antd封装的公共组件的自动化测试技术的选型和实践. 背景 随着前端项目越来越大,业务逻辑日益繁杂,协 ...

  4. react 单元测试 (jest+enzyme)

    为什么要做单元测试 作为一个前端工程师,我是很想去谢单元测试的,因为每天的需求很多,还要去编写测试代码,感觉时间都不够用了. 不过最近开发了一个比较复杂的项目,让我感觉一旦项目大了.复杂了,而且还是多 ...

  5. 用React.addons.TestUtils、Jasmine进行单元测试

    一.用到的工具 1.React.addons.TestUtils 2.Jasmine 3.Browserify(处理jsx文件的require依赖关系) 4.Reactify(能和browserify ...

  6. 【前端单元测试入门05】react的单元测试之jest

    jest jest是facebook推出的一款测试框架,集成了前面所讲的Mocha和chai,jsdom,sinon等功能. 安装 npm install --save-dev jest npm in ...

  7. MVC、MVP、MVVM、Angular.js、Knockout.js、Backbone.js、React.js、Ember.js、Avalon.js、Vue.js 概念摘录

    注:文章内容都是摘录性文字,自己阅读的一些笔记,方便日后查看. MVC MVC(Model-View-Controller),M 是指业务模型,V 是指用户界面,C 则是控制器,使用 MVC 的目的是 ...

  8. [译]Thinking in React

    编者按 使用React的思想来构建应用对我在实际项目中以及帮助他人解决实际问题时起到了很大作用,所以我翻译此文来向那些正在或即将陷入React或React-Native深坑的同胞们表示慰问.网上已经有 ...

  9. React Test相关资料

    karma 前端测试驱动器,生产测试报告,多个浏览器 mocha js的测试框架,相当于junit chai,单元测试的断言库,提供expect shudl assert enzyme sinon.j ...

随机推荐

  1. 写代码质量改善java计划151建议——导航开始

    2014-05-16 09:08 by Jeff Li 前言 系列文章:[传送门] 下个星期度过这几天的奋战,会抓紧java的进阶学习.听过一句话,大哥说过,你一个月前的代码去看下,慘不忍睹是吧.确实 ...

  2. 阿里云server(ECS)优惠券领取

    CoderMan的博客也是放置在阿里云的ECS上.速度绝对是刚刚的,大家打开的速度肯定不会慢. 有些同志们至今可能还在用虚拟主机吧,其实阿里云server真心不贵,有俩种计费方式:各自是按月计费和按流 ...

  3. ORACLE函数之日期时间运算函数

    1            ADD_MONTHS 格式:ADD_MONTHS(D,N) 说明:返回日期时间D加N月后相应的日期时间.N为正时则表示D之后:N为负时则表示为D之前.N为小数则会自己主动先删 ...

  4. SDL2源码分析5:更新纹理(SDL_UpdateTexture())

    ===================================================== SDL源码分析系列文章列表: SDL2源码分析1:初始化(SDL_Init()) SDL2源 ...

  5. MyEclipse中“擅自乱改”项目名导致项目报错的处理

    最近几天培训的过程中,经常有同学手一抖,默默的修改了本来配置部署好的项目名,导致项目报错…… 遇到这种事情,我一般会做的处理就是重新新建项目,然后把包和各种文件ctrl+c ctrl+v,遇到项目小还 ...

  6. windows phone 页面导航(6)

    原文:windows phone 页面导航(6) 页面导航的例子我们使用的是两个页面,从第一个页面(MainPage)导航到第二个页面(SecondPage),然后可以从第二个页面导航到第一个页面 , ...

  7. Windows Phone开发(14):数据模板

    原文:Windows Phone开发(14):数据模板 数据模板,如果你仅仅听到这个名词,你一定很迷惑,什么来的?用来干什么的?不急,亲,今天,我们一起来探索一下吧. 用白话文说,数据模板就是用来规范 ...

  8. C语言 cgi(2)

    1Columbia Universitycs3157 – Advanced ProgrammingSummer 2014, Lab #3, 40 pointsJune 10, 2014This lab ...

  9. 安装sunvirtualbox

    按照网友提供的方法安装sunvirtualbox,老提示:依赖关系不满足: libpython2.6 (>= 2.6) 后来用终端运行 sudo apt-get install virtualb ...

  10. Codeforces Round #256 (Div. 2) A. Rewards

    A. Rewards time limit per test 1 second memory limit per test 256 megabytes input standard input out ...