当面对现在流行的React+Redux创建的Web应用时,该如何用Mocha+Chai进行测试?
搭建测试基础框架
为了搭建搭建框架,我们需要做以下几个事:
- 设置一个类浏览器的命令行测试环境
- 创建一个‘renderComponent’函数来render react class
- 模拟事件simulating events
- 设置chai-jquery
下面详细解释这几个事情
搭建一个类浏览器的命令行测试环境
使用自动化工具(Webpack,browserify)构建出来的web应用,几乎所有的内容都浓缩在bundle.js里了。
不同于浏览器,terminal环境要解析Ract中的DOM,以及一些全局变量就需要工具了,
这里我们采用jsdom来模拟DOM结构。
再将这个DOM结构封装成jquery对象。1
2
3
4
5
6import jsdom from 'jsdom';
import jquery from 'jquery';
global.document = jsdom.jsdom('<!doctype html><html><body></body></html>');
global.window = global.document.defaultView;
const $ = jquery(global.window);
创建一个‘renderComponent’函数来render react class
写React应用时最常用的方法render就是将React的组件渲染成DOM(或者虚拟DOM),所以在测试之前,我们创建一个renderComponent方法,将React的组件渲染出来。
用ReactTestUtils的renderIntoDocument方法,将一个组件渲染成DOM node。1
2
3ReactComponent renderIntoDocument(
ReactElement instance
)
当我们使用Redux的时候,需要用Provider来渲染组件,参数分别为组件的props和Redux的state(store),因为Redux只有一个store,所以使用起来还是比较方便的。
生成的组件instance用findDOMNode方法获取真实DOM节点,并绑定成jquery对象。
1 | import TestUtils from 'react-addons-test-utils'; |
这样,通过renderComponent方法,就可以将一个react组件转换成dom节点并返回。
模拟事件simulating events
有时候,我们需要模拟一些事件来满足我们的测试需求,例如点击button,按下键盘,输入文字等。
这部分我们用ReactTestUtils的simulate方法来实现。
1 | $.fn.simulate = function(eventName, value) { |
设置chai-jquery
设置一下chai-jquery,具体参看官方网页。1
2
3import chai, { expect } from 'chai';
import chaiJquery from 'chai-jquery';
chaiJquery(chai, chai.util, $);
export方法
最后不要忘了把renderComponent和chai的expect export出去1
export { renderComponent, expect };
test_helper.js
以上内容可以合成到一个js文件中1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42import jsdom from 'jsdom';
import jquery from 'jquery';
import TestUtils from 'react-addons-test-utils';
import ReactDOM from 'react-dom';
import chai, { expect } from 'chai';
import React from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import reducers from '../src/reducers';
import chaiJquery from 'chai-jquery';
// 设置一个类浏览器的命令行测试环境
global.document = jsdom.jsdom('<!doctype html><html><body></body></html>');
global.window = global.document.defaultView;
const $ = jquery(global.window);
// 创建一个‘renderComponent’函数来render react class
function renderComponent(ComponentClass, props, state) {
// React Add-Ons : renderIntoDocument
const componentInstance = TestUtils.renderIntoDocument(
<Provider store={createStore(reducers, state)}>
<ComponentClass {...props} />
</Provider>
);
return $(ReactDOM.findDOMNode(componentInstance));
}
// 模拟事件simulating events
$.fn.simulate = function(eventName, value) {
if (value) {
this.val(value);
}
TestUtils.Simulate[eventName](this[0]);
}
// set up chai-jquery
chaiJquery(chai, chai.util, $);
export { renderComponent, expect };
如何使用test_helper.js
说了半天只不过写了一个测试工具框架而已,下面说说怎么使用这个工具。
假设我们有一个评论APP,有一个评论框,下面是评论列表
APP1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import React from 'react';
import { Component } from 'react';
import CommentBox from './comment_box';
import CommentList from './comment_list';
export default class App extends Component {
render() {
return (
<div>
<CommentBox />
<CommentList />
</div>
);
}
}
测试案例
- 有一个comment box (这里检查是否包含comment-box class)
- 有一个comment list (这里检查是否包含comment-list class)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21import { renderComponent, expect } from '../test_helper';
import App from '../../src/components/app';
// 使用describe把相似的测试结合起来
describe('App', () => {
let component;
beforeEach(() => {
component = renderComponent(App);
});
// 使用it测试一个目标的一个行为
it('shows a comment box', () => {
// 使用expect断言一个目标
expect(component.find('.comment-box')).to.exist;
});
it('shows a comment list', () => {
expect(component.find('.comment-list')).to.exist;
});
});
再做一个CommentBox的测试案例:
- 有一个textarea
- 有一个button
- 在textarea中显示输入的文字
- 当提交后清空textarea
1 | import { renderComponent, expect } from '../test_helper'; |
如何跑测试
在package.json的script中添加测试命令1
2"test": "mocha --compilers js:babel-core/register --require ./test/test_helper.js --recursive ./test",
"test:watch": "npm run test -- --watch"
需要测试的时候1
npm run test:watch
就可以了。