一个完整、优秀的项目往往离不开单元测试的环节,就 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. Maven系列第9篇:多环境构建支持,核心开发必备!

    maven系列目标:从入门开始开始掌握一个高级开发所需要的maven技能. 这是maven系列第9篇. 整个maven系列的内容前后是有依赖的,如果之前没有接触过maven,建议从第一篇看起,本文尾部 ...

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

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

  3. Hyperledger Fabric 1.0 从零开始(三)——环境构建(内网/准离线)

    有公网环境的服务器可以直接看 Hyperledger Fabric 1.0 从零开始(二)--环境构建(公网) ,本篇内容与上篇相似,只不过环境搭建需要在内网下,也就是网络被限制的情况下. 1:环境构 ...

  4. Hyperledger Fabric 1.0 从零开始(二)——环境构建(公网)

    1:环境构建 在本文中用到的宿主机环境是Centos ,版本为Centos.x86_647.2,通过Docker 容器来运行Fabric的节点,版本为v1.0.因此,启动Fabric网络中的节点需要先 ...

  5. SSM框架整合环境构建——基于Spring4和Mybatis3

    目录 环境 配置说明 所需jar包 配置db.properties 配置log4j.properties 配置spring.xml 配置mybatis-spring.xml 配置springmvc.x ...

  6. React 与 Redux 在生产环境中的实践总结

    React 与 Redux 在生产环境中的实践总结 前段时间使用 React 与 Redux 重构了我们360netlab 的 开放数据平台.现将其中一些技术实践经验总结如下: Universal 渲 ...

  7. Cocos2d-x v3.1 GUI系统--环境构建(七)

    Cocos2d-x v3.1 GUI系统--环境构建(七) 在使用Cocos2d-x的GUI系统时,由于生成的工程默认是没有将GUI系统所需的库导入到项目的,所以我们必须把库导入到工程中并对工程做一些 ...

  8. 如何从零搭建一个webpack+react+redux+react-redux的开发环境一入门

    阅读本文章的时候,你要有一定的基础知识储备,简单的es6知识,模块化思想知识,js基础知识,node基础知识,react等 首先执行npm init,此时我的文件叫case; 下面安装一些需要的npm ...

  9. jQuery2.x源码解析(构建篇)

    jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 笔者阅读了园友艾伦 Aaron的系列博客< ...

随机推荐

  1. .NET Core系列 :4 测试

    2016.6.27 微软已经正式发布了.NET Core 1.0 RTM,但是工具链还是预览版,同样的大量的开源测试库也都是至少发布了Alpha测试版支持.NET Core, 这篇文章 The Sta ...

  2. 工厂方法模式——创建型模式02

    1. 简单工厂模式     在介绍工厂方法模式之前,先介绍一下简单工厂模式.虽然简单工厂模式不属于GoF 23种设计模式,但通常将它作为学习其他工厂模式的入门,并且在实际开发中使用的也较为频繁. (1 ...

  3. Android Ormlite 学习笔记1 -- 基础

    Ormlite 是一个开源Java数据实体映射框架.其中依赖2个核心类库: 1.ormlite-android-4.48.jar 2.ormlite-core-4.48.jar 新建项目,引用上面2个 ...

  4. scrapy爬虫docker部署

    spider_docker 接我上篇博客,为爬虫引用创建container,包括的模块:scrapy, mongo, celery, rabbitmq,连接https://github.com/Liu ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统(66)-MVC WebApi 用户验证 (2)

    系列目录 前言: 回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手. 继续上一篇的文章,我们接下来演示利用拿到的Token来访 ...

  6. 一起学 Java(二)面向对象

    一.方法函数 函数也称为方法,就是定义在类中的具有特定功能的一段独立代码.用于定义功能,提高代码的复用性. 函数的特点1> 定义函数可以将功能代码进行封装,便于对该功能进行复用:2> 函数 ...

  7. CSS 3学习——transform 2D转换

    首先声明一点,transform属性不为none的元素是它的定位子元素(绝对定位和固定定位)的包含块,而且对内创建一个新的层叠上下文. 注意:可以通过 transform-box 属性指定元素的那个盒 ...

  8. DevExpress - 使用 GaugeControl 标尺组件制作抽奖程序 附源码

    前不久,公司举办了15周年庆,其中添加了一个抽奖环节,要从在读学员中随机抽取幸运学员,当然,这个任务就分到了我这里. 最后的效果如下,启动有个欢迎页面,数据是来自Excel的,点击开始则上面的学号及姓 ...

  9. 札记:Java异常处理

    异常概述 程序在运行中总会面临一些"意外"情况,良好的代码需要对它们进行预防和处理.大致来说,这些意外情况分三类: 交互输入 用户以非预期的方式使用程序,比如非法输入,不正当的操作 ...

  10. 【流量劫持】沉默中的狂怒 —— Cookie 大喷发

    精简版:http://www.cnblogs.com/index-html/p/mitm-cookie-crack.html 前言 上一篇文章 讲解了如何借助前端技术,打造一个比 SSLStrip 更 ...