前端单元测试探索

发表于:2016-9-20 11:05

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:ecmadao    来源:51Testing软件测试网采编

分享:
  initial
  下面两篇文章值得一看:
  Testing in ES6 with Mocha and Babel 6
  Using Babel
  setup
  $ npm i mocha --save-dev
  $ npm i chai --save-dev
  Use with es6
  babel 6+
$ npm install --save-dev babel-register
$ npm install babel-preset-es2015 --save-dev
// package.json
{
"scripts": {
"test": "./node_modules/mocha/bin/mocha --compilers js:babel-register"
},
"babel": {
"presets": [
"es2015"
]
}
}
  babel 5+
$ npm install --save-dev babel-core
// package.json
{
"scripts": {
"test": "./node_modules/mocha/bin/mocha --compilers js:babel-core/register"
}
}
  Use with coffeescript
$ npm install --save coffee-script
{
"scripts": {
"test": "./node_modules/mocha/bin/mocha --compilers coffee:coffee-script/register"
}
}
  Use with es6+coffeescript
  After done both...
{
"scripts": {
"test": "./node_modules/mocha/bin/mocha --compilers js:babel-core/register,coffee:coffee-script/register"
}
}
# $ mocha
$ npm t
$ npm test
  chai
import chai from 'chai';
const assert = chai.assert;
const expect = chai.expect;
const should = chai.should();
foo.should.be.a('string');
foo.should.equal('bar');
list.should.have.length(3);
obj.should.have.property('name');
expect(foo).to.be.a('string');
expect(foo).to.equal('bar');
expect(list).to.have.length(3);
expect(obj).to.have.property('flavors');
assert.typeOf(foo, 'string');
assert.equal(foo, 'bar');
assert.lengthOf(list, 3);
assert.property(obj, 'flavors');
  Test
  测试的一个基本思路是,自身从函数的调用者出发,对函数进行各种情况的调用,查看其容错程度、返回结果是否符合预期。
import chai from 'chai';
const assert = chai.assert;
const expect = chai.expect;
const should = chai.should();
describe('describe a test', () => {
it('should return true', () => {
let example = true;
// expect
expect(example).not.to.equal(false);
expect(example).to.equal(true);
// should
example.should.equal(true);
example.should.be.a(boolen);
[1, 2].should.have.length(2);
});
it('should check an object', () => {
// 对于多层嵌套的Object而言..
let nestedObj = {
a: {
b: 1
}
};
let nestedObjCopy = Object.assign({}, nestedObj);
nestedObj.a.b = 2;
// do a function to change nestedObjCopy.a.b
expect(nestedObjCopy).to.deep.equal(nestedObj);
expect(nestedObjCopy).to.have.property('a');
});
});
  AsynTest
  Testing Asynchronous Code with MochaJS and ES7 async/await
  mocha无法自动监听异步方法的完成,需要我们在完成之后手动调用 done() 方法
  而如果要在回调之后使用异步测试语句,则需要使用 try/catch 进行捕获。成功则 done() ,失败则 done(error)
// 普通的测试方法
it("should work", () =>{
console.log("Synchronous test");
});
// 异步的测试方法
it("should work", (done) =>{
setTimeout(() => {
try {
expect(1).not.to.equal(0);
done(); // 成功
} catch (err) {
done(err); // 失败
}
}, 200);
});
  异步测试有两种方法完结: done 或者返回 Promise 。而通过返回 Promise ,则不再需要编写笨重的 try/catch 语句
  it("Using a Promise that resolves successfully with wrong expectation!", function() {
  var testPromise = new Promise(function(resolve, reject) {
  setTimeout(function() {
  resolve("Hello World!");
  }, 200);
  });
  return testPromise.then(function(result){
  expect(result).to.equal("Hello!");
  });
  });
  mock
  mock是一个接口模拟库,我们可以通过它来模拟代码中的一些异步操作
  React单元测试
  Test React Component
  React组件无法直接通过上述方法进行测试,需要安装enzyme依赖。
  $ npm i --save-dev enzyme
  #
  $ npm i --save-dev react-addons-test-utils
  假设有这样一个组件:
// ...省略部分import代码
class TestComponent extends React.Component {
constructor(props) {
super(props);
let {num} = props;
this.state = {
clickNum: num
}
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
let {clickNum} = this.state;
this.setState({
clickNum: clickNum + 1
});
}
render() {
let {clickNum} = this.state;
return (
<div className="test_component">
{clickNum}
<span onClick={this.handleClick}>点我加1</span>
</div>
)
}
}
  使用样例:
import React from 'react';
import {expect} from 'chai';
import {shallow} from 'enzyme';
import TestComponent from '../components/TestComponent';
describe('Test TestComponent', () => {
// 创建一个虚拟的组件
const wrapper = shallow(
<TestComponent num={10} />/
);
/*
* 之后,我们可以:
* 通过wrapper.state()拿到组件的state
* 通过wrapper.instance()拿到组件实例,以此调用组件内的方法
* 通过wrapper.find()找到组件内的子组件
* 但是,无法通过wrapper.props()拿到组件的props
*/
// 测试该组件组外层的class
it('should render with currect wrapper', () => {
expect(wrapper.is('.test_component')).to.equal(true);
});
// 测试该组件初始化的state
it('should render with currect state', () => {
expect(wrapper.state()).to.deep.equal({
clickNum: 10
});
});
// 测试组件的方法
it('should add one', () => {
wrapper.instance().handleClick();
expect(wrapper.state()).to.deep.equal({
clickNum: 11
});
});
});
  Test Redux
  redux身为纯函数,非常便于mocha进行测试
// 测试actions
import * as ACTIONS from '../redux/actions';
describe('test actions', () => {
it('should return an action to create a todo', () => {
let expectedAction = {
type: ACTIONS.NEW_TODO,
todo: 'this is a new todo'
};
expect(ACTIONS.addNewTodo('this is a new todo')).to.deep.equal(expectedAction);
});
});
// 测试reducer
import * as REDUCERS from '../redux/reducers';
import * as ACTIONS from '../redux/actions';
describe('todos', () => {
let todos = [];
it('should add a new todo', () => {
todos.push({
todo: 'new todo',
complete: false
});
expect(REDUCERS.todos(todos, {
type: ACTIONS.NEW_TODO,
todo: 'new todo'
})).to.deep.equal([
{
todo: 'new todo',
complete: false
}
]);
});
});
// 还可以和store混用
import { createStore, applyMiddleware, combineReducers } from 'redux';
import thunk from 'redux-thunk';
import chai from 'chai';
import thunkMiddleware from 'redux-thunk';
import * as REDUCERS from '../redux/reducers';
import defaultState from '../redux/ConstValues';
import * as ACTIONS from '../redux/actions'
const appReducers = combineReducers(REDUCERS);
const AppStore = createStore(appReducers, defaultState, applyMiddleware(thunk));
let state = Object.assign({}, AppStore.getState());
// 一旦注册就会时刻监听state变化
const subscribeListener = (result, done) => {
return AppStore.subscribe(() => {
expect(AppStore.getState()).to.deep.equal(result);
done();
});
};
describe('use store in unittest', () => {
it('should create a todo', (done) => {
// 首先取得我们的期望值
state.todos.append({
todo: 'new todo',
complete: false
});
// 注册state监听
let unsubscribe = subscribeListener(state, done);
AppStore.dispatch(ACTIONS.addNewTodo('new todo'));
// 结束之后取消监听
unsubscribe();
});
});
  基于 phantomjs 和selenium的UI UnitTest
  PhantomJS 是一个基于webkit的服务器端JavaScript API,即相当于在内存中跑了个无界面的webkit内核的浏览器。通过它我们可以模拟页面加载,并获取到页面上的DOM元素,进行一系列的操作,以此来模拟UI测试。但缺点是无法实时看见页面上的情况(不过可以截图)。
  而 Selenium 是专门为Web应用程序编写的一个验收测试工具,它直接运行在浏览器中。 Selenium 测试通常会调起一个可见的界面,但也可以通过设置,让它以 PhantomJS 的形式进行无界面的测试。
  · open 某个 url
  · 监听 onload 事件
  · 事件完成后调用 sendEvent 之类的 api 去点击某个 DOM 元素所在 point
  · 触发交互
  · 根据 UI 交互情况 延时 setTimeout (规避惰加载组件点不到的情况)继续 sendEvent 之类的交互
22/2<12
精选软件测试好文,快来阅读吧~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号