虽然很多公司有自己的测试部门,而且前端开发大多不涉及测试环节,但鉴于目前前端领域的快速发展,其涉及面越来越广,前端开发者们必然不能止步于目前的状态。我觉得学会编写良好的测试,不仅仅有利于自己整理需求、检查代码,更是一个优秀开发者的体现。
在民和等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供成都网站制作、做网站 网站设计制作按需求定制设计,公司网站建设,企业网站建设,成都品牌网站建设,成都全网营销,成都外贸网站建设,民和网站建设费用合理。
首先不得不推荐两篇文章:
Intro
单元测试到底是什么?
需要访问数据库的测试不是单元测试
需要访问网络的测试不是单元测试
需要访问文件系统的测试不是单元测试
--- 修改代码的艺术
我们在单元测试中应该避免什么?
TDD(Test-driven development)
测试驱动开发(TDD),其基本思路是通过测试来推动整个开发的进行。
IMPORTANT
大致过程
* 每个概念都被清晰的表达
* Not Repeat Self
* 没有多余的东西
* 通过测试
BDD(Behavior-driven development)
行为驱动开发(BDD),重点是通过与利益相关者的讨论,取得对预期的软件行为的清醒认识,其重点在于沟通
大致过程
测试的分类 & 测试工具
分类
* 测试不常变化的函数逻辑
* 测试前后端API接口
* 页面自动截图
* 页面DOM元素检查
* 跑通交互流程
工具
* with python
* with js
mocha + chai的API/Func UnitTest
mocha是一套前端测试工具,我们可以拿它和其他测试工具搭配。
而chai则是BDD/TDD测试断言库,提供诸如expect这样的测试语法
initial
下面两篇文章值得一看:
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 (
- {clickNum}
- 点我加1
- )
- }
- }
使用样例:
- import React from 'react';
- import {expect} from 'chai';
- import {shallow} from 'enzyme';
- import TestComponent from '../components/TestComponent';
- describe('Test TestComponent', () => {
- // 创建一个虚拟的组件
- const wrapper = shallow(
/ - );
- /*
- * 之后,我们可以:
- * 通过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的形式进行无界面的测试。
Getting started with Selenium Webdriver for node.js
分享名称:前端单元测试探索
本文网址:http://www.shufengxianlan.com/qtweb/news48/269098.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联