React组件测试
去年React旋风一般席卷全球,当然天猫也在技术上紧跟时代脚步。天猫商家端业务已经全面切入React,形成了React组件体系,几乎所有新业务都采用React开发,而老业务也在不断向React迁移。React大红大紫,这里单独拉出来讲一讲React+webpack的打包方案如何进行测试
这里只聊React Web,不聊React Native
事实上天猫目前并未采用webpack打包,而是Gulp+Babel编译React CommonJS代码成AMD模块使用,这是为了能够在新老业务使用上更加灵活,当然也有部分业务采用webpack打包并上线
叕一个煎蛋的栗子
这里创建一个React组件,目录结构大致这样(这里略过CSS相关部分,只要跑通了,集成CSS像PostCSS、Less都没啥问题):
.
├── demo
├── karma.conf.js
├── package.json
├── src
│ └── index.jsx
├── test
│ └── index_spec.jsx
├── webpack.dev.js
└── webpack.pub.js
React组件源码src/index.jsx大概是这个样子:
import React from 'react';
class Welcome extends React.Component {
constructor() {
super();
}
render() {
return
}
}
Welcome.displayName = 'Welcome';
Welcome.propTypes = {
/**
* content of element
*/
content: React.PropTypes.string
};
Welcome.defaultProps = {
content: 'Hello Tmall'
};
module.exports = Welcome;
那么对应的test/index_spec.jsx则大概是这个样子:
import 'should';
import Welcome from '../src/index.jsx';
import ReactDOM from 'react-dom';
import React from 'react';
import TestUtils from 'react-addons-test-utils';
describe('test', function() {
const container = document.createElement('div');
document.body.appendChild(container);
afterEach(() => {
ReactDOM.unmountComponentAtNode(container);
});
it('Hello Tmall', function() {
let cp = ReactDOM.render(, container);
let welcome = TestUtils.findRenderedComponentWithType(cp, Welcome);
ReactDOM.findDOMNode(welcome).textContent.should.be.eql('Hello Tmall');
});
});
由于是测试React,自然要使用React的TestUtils,这个工具库提供了不少方便查找节点和组件的方法,最重要的是它提供了模拟事件的API,这可以说是UI测试最重要的一个功能。更多关于TestUtils的使用请参考React官网,这里就不扯了...
代码有了,测试用例也有了,接下就差跑起来了。karma.conf.js肯定就和上面不一样了,首先它要多一个插件karma-webpack,因为我们的React组件是需要webpack打包的,不打包的代码压根就没法运行。另外还需要注意代码覆盖率测试也出现了变化。因为现在多了一层Babel编译,Babel编译ES6、ES7源码生成ES5代码后会产生很多polyfill代码,因此如果对build完成之后的代码做覆盖率测试会包含这些polyfill代码,这样测出来的覆盖率显然是不可靠的,这个问题可以通过isparta-loader来解决。React组件的karma.conf.js大概是这个样子:
'use strict';
const path = require('path');
module.exports = function(config) {
config.set({
frameworks: ['mocha'],
files: [
'./node_modules/phantomjs-polyfill/bind-polyfill.js',
'test/**/*_spec.jsx'
],
plugins: ['karma-webpack', 'karma-mocha',, 'karma-chrome-launcher', 'karma-firefox-launcher', 'karma-phantomjs-launcher', 'karma-coverage', 'karma-spec-reporter'],
browsers: ['PhantomJS', 'Firefox', 'Chrome'],
preprocessors: {
'test/**/*_spec.jsx': ['webpack']
},
reporters: ['spec', 'coverage'],
coverageReporter: {
dir: 'coverage',
reporters: [{
type: 'json',
subdir: '.',
file: 'coverage.json',
}, {
type: 'lcov',
subdir: '.'
}, {
type: 'text-summary'
}]
},
webpack: {
module: {
loaders: [{
test: /\.jsx?/,
loaders: ['babel']
}],
preLoaders: [{
test: /\.jsx?$/,
include: [path.resolve('src/')],
loader: 'isparta'
}]
}
},
webpackMiddleware: {
noInfo: true
}
});
};
这里相对于之前的karma.conf.js,主要有以下几点区别:
由于webpack的打包功能,我们在测试代码里直接import组件代码,因此不再需要在files里手动引入组件代码
预处理里面需要对每个测试文件都做webpack打包
添加webpack编译相关配置,在编译源码时,需要定义preLoaders,并使用isparta-loader做代码覆盖率打点
添加webpackMiddleware配置,这里noInfo作用是不需要输出webpack编译时那一大串信息
这样配置基本上就完成了,跑一把./node_modules/karma/bin/karma start --single-run:
很好,结果符合预期。open coverage/lcov-report/index.html打开覆盖率页面:
鹅妹子音!!!直接对jsx代码做的覆盖率测试!这样React组件的测试大体上就完工了
小结
前端的代码测试主要难度是如何模拟各种各样的浏览器环境,Karma给我们提供了很好地方式,对于本地有的浏览器能自动打开并测试,本地没有的浏览器则提供直接访问的页面。前端尤其是移动端浏览器种类繁多,很难做到完美,但我们可以通过这种方式实现主流浏览器的覆盖,保证每次上线大多数用户没有问题。
持续集成
测试结果有了,接下来就是把这些测试结果接入到持续集成之中。持续集成是一种非常优秀的多人开发实践,通过代码push触发钩子,实现自动运行编译、测试等工作。接入持续集成后,我们的每一次push代码,每个Merge Request都会生成对应的测试结果,项目的其他成员可以很清楚地了解到新代码是否影响了现有的功能,在接入自动告警后,可以在代码提交阶段就快速发现错误,提升开发迭代效率。
持续集成会在每次集成时提供一个几乎空白的虚拟机器,并拷贝用户提交的代码到机器本地,通过读取用户项目下的持续集成配置,自动化的安装环境和依赖,编译和测试完成后生成报告,在一段时间之后释放虚拟机器资源。
开源的持续集成
开源比较出名的持续集成服务当属Travis,而代码覆盖率则通过Coveralls,只要有GitHub账户,就可以很轻松的接入Travis和Coveralls,在网站上勾选了需要持续集成的项目以后,每次代码push就会触发自动化测试。这两个网站在跑完测试以后,会自动生成测试结果的小图片
Travis会读取项目下的travis.yml文件,一个简单的例子:
language: node_js
node_js:
- "stable"
- "4.0.0"
- "5.0.0"
script: "npm run test"
after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls"
language定义了运行环境的语言,而对应的node_js可以定义需要在哪几个Node.js版本做测试,比如这里的定义,代表着会分别在最新稳定版、4.0.0、5.0.0版本的Node.js环境下做测试
而script则是测试利用的命令,一般情况下,都应该把自己这个项目开发所需要的命令都写在package.json的scripts里面,比如我们的测试方法./node_modules/karma/bin/karma start --single-run就应当这样写到scripts里:
{
"scripts": {
"test": "./node_modules/karma/bin/karma start --single-run"
}
}
而after_script则是在测试完成之后运行的命令,这里需要上传覆盖率结果到coveralls,只需要安装coveralls库,然后获取lcov.info上传给Coveralls即可
更多配置请参照Travis官网介绍
这样配置后,每次push的结果都可以上Travis和Coveralls看构建和代码覆盖率结果了
小结
项目接入持续集成在多人开发同一个仓库时候能起到很大的用途,每次push都能自动触发测试,测试没过会发生告警。如果需求采用Issues+Merge Request来管理,每个需求一个Issue+一个分支,开发完成后提交Merge Request,由项目Owner负责合并,项目质量将更有保障
总结
这里只是前端测试相关知识的一小部分,还有非常多的内容可以深入挖掘,而测试也仅仅是前端流程自动化的一部分。在前端技术快速发展的今天,前端项目不再像当年的刀耕火种一般,越来越多的软件工程经验被集成到前端项目中,前端项目正向工程化、流程化、自动化方向高速奔跑。还有更多优秀的提升开发效率、保证开发质量的自动化方案亟待我们挖掘。
一篇看不够?你需要的是这门系统专业课程:
33/3<123