热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

怎样运用mocha和sinon集成单元测试单元测试示例及剖析(上)

运用mocha集成单位测试(上)项目地点:https:github.comJay-tianj…装置依靠yarnaddjquerymochamochawesomeistanbulsi
运用 mocha 集成单位测试(上)

项目地点:
https://github.com/Jay-tian/j…

装置依靠

yarn add jquery mocha mochawesome istanbul sinon chai jsdom decache babel-cli babel-core babel-preset-es2015 babel-plugin-module-resolver babel-istanbul

mocha:测试框架
mochawesome:可视化报表
istanbul:覆蓋率
sinon:替代依靠
chai:断言

scripts 敕令

敕令

"scripts": {
"test": "mocha --timeout 5000 --recursive --reporter mochawesome --require babel-core/register tests/src && open mochawesome-report/mochawesome.html && npm run test:cover",
"test:cover": "babel-node ./node_modules/.bin/babel-istanbul cover _mocha -- tests/src/* -R spec --recursive && open coverage/lcov-report/index.html",
"test:s": "mocha --recursive --require babel-core/register --timeout 5000"
}

test 敕令:实行单位测试,并翻开测试报告页面和覆蓋率页面
test:cover 实行天生单位测试覆蓋率并翻开
test:s 实行单个单位测试文件

参数剖析

–timeout 5000 超时设置
–recursive 包括子目次
–reporter mochawesome 经由过程mochawesome天生报表
–require babel-core/register 经由过程babel转译es6语法
tests/src 单位测试目次途径
open mochawesome-report/mochawesome.html 翻开页面

测试含有jQuery的代码

初始化Jquery环境

let { JSDOM } = require('jsdom');
let dom = new JSDOM(``,{
url: 'http://127.0.0.1',
referrer: 'http://127.0.0.1',
contentType: 'text/html',
userAgent: 'Mellblomenator/9000',
includeNodeLocations: true,
});
global.window = dom.window;
global.$ = require('jquery');

测试click事宜

const { demo1 } = require('../../src/demo1.js');
const assert = require('chai').assert;
describe('demo1', function() {
it('jquery click test', function() {
demo1($('body'));
assert.equal($('body').hasClass('hide'), false);
$('body').trigger('click');
assert.equal($('body').hasClass('hide'), true);
});
});

运转效果

以上测试了,点击元素时,给该元素增加一个‘hide’类的要领
模仿jquery环境和触发click事宜
《怎样运用 mocha 和 sinon 集成单元测试--单元测试示例及剖析(上)》

测试post事宜

由于初始化jquery环境比较通用,我们把它放到东西类去援用

utils.js

const decache = require('decache');
let { JSDOM } = require('jsdom');
exports.initJquery = function(html, params = {}){
params = Object.assign({
url: 'http://127.0.0.1',
referrer: 'http://127.0.0.1',
contentType: 'text/html',
userAgent: 'Mellblomenator/9000',
includeNodeLocations: true,
}, params);
let dom = new JSDOM(`${html}`, params);
global.window = dom.window;
decache('jquery');
global.$ = require('jquery');
}

由于node环境中,require会有缓存,致使差别的单位测试间的初始环境不一致,须要手动消灭缓存

decache('jquery');

test.demo2.js

import post from '../../src/demo2.js';
const utils = require('./../utils');
const sinon = require('sinon');
require('./../utils');
describe('demo2', function() {
before(function() {
utils.initJquery('');
}); it('jquery post', function() {
let stubPost = sinon.stub($, 'post');
let expectedUrl = '/demo2';
let expectedParams = {'a': 'abc'};
post();
sinon.assert.calledWith(stubPost, expectedUrl, expectedParams);
stubPost.restore();
});
});

restore()操纵 将会回复被替代的对象
mocha 有四个钩子要领
before 在一切的单位测试运转前运转一次
after 在一切的单位测试运转完毕运转一次
beforeEach 在每个的单位测试运转前运转一次
afterEach 在每个的单位测试运转后运转一次

测试ajax

demo3.js

export default function() {
$.ajax({
type: 'GET',
url: null,
async: true,
promise: true,
dataType: 'json',
beforeSend(request) {
}
});
}

test.demo3.js

import ajax from '../../src/demo3.js';
const utils = require('./../utils');
const sinon = require('sinon');
require('./../utils');
describe('demo3', function() {
before(function() {
utils.initJquery('');
}); it('jquery ajax', function() {
let stubAjax = sinon.stub($, 'ajax');
let expectedParams = {
type: 'GET',
url: null,
async: true,
promise: true,
dataType: 'json'
};
ajax();
sinon.assert.calledWithMatch(stubAjax, expectedParams);
stubAjax.restore();
});
});

这里我们运用calledWithMatch断言参数,该要领能够断言传入的参数是不是准确,不须要传入一切的参数

测试异步代码

demoe4.js

export default function() {
$('#demo4').hide();
setTimeout(
function(){
$('#demo4').show();
}, 1000);
}

import demo4 from '../../src/demo4.js';
const utils = require('./../utils');
const sinon = require('sinon');
const assert = require('chai').assert;
require('./../utils');
describe('asynchronous code', function() {
let clock;
before(function () {
utils.initJquery('

');

});
it('test by setTimeout', function(done) {
let $demo = $('#demo4');
demo4();
assert.equal($demo.css('display'), 'none');
let test = function() {
assert.equal($demo.css('display'), 'block');
// 这里的done示知这个单位测试完毕了,保证不影响其他单位测试
done();
};
setTimeout(test, 1001);
});
it('test by sinon', function() {
//当利用了useFakeTimers后,事宜将会住手
clock = sinon.useFakeTimers();
let $demo = $('#demo4');
//运转demo4前,元素照样显现的
assert.equal($demo.css('display'), 'block');
demo4();
//运转demo4完,元素隐蔽了
assert.equal($demo.css('display'), 'none');
//时候穿越101ms秒,定时器代码还未实行,所以元素照样隐蔽的
clock.tick(101);
assert.equal($demo.css('display'), 'none');
//时候再穿越900ms秒,就抵达了1001ms后,定时器代码实行了,所以元素如今显现了
clock.tick(900);
assert.equal($demo.css('display'), 'block');
//恢复时候
clock.restore();
});
});

第一个单位测试利用了 setTimeout 去测试异步代码
第二个单位测试利用了 sinon 的时空穿越器去测试异步代码
效果如图所示
《怎样运用 mocha 和 sinon 集成单元测试--单元测试示例及剖析(上)》

第一个单位测试花了1035ms
而第二个单位测试几乎没有消费若干时候

所以异步代码编写单位测试时,第二个单位测试写法更优

须要测试的代码包括其他担任营业逻辑时

demo5.js

const demo5require = require('./demo5.require.js');
export default function() {
if(demo5require.a() == 'a') {
return 1;
} else {
return 2;
}
}

test.demo5.js

import demo5 from '../../src/demo5.js';
const utils = require('./../utils');
const sinon = require('sinon');
const assert = require('chai').assert;
describe('demo5', function() {
before(function () {
utils.initJquery('');
});
it('test', function() {
assert.equal(demo5(), 1);
const demo5require = require('../../src/demo5.require.js');
let stub = sinon.stub(demo5require, 'a').returns('b');
assert.equal(demo5(), 2);
stub.restore();
});
});

此时demo5依靠其他模块,我们就能够替代demo5require的要领,并指定返回值,如许就不必关联依靠的模块做了什么营业。
测试完毕,回复被替代的对象

webpack环境编写单位测试

webpack中会有设置别号的状况,如许单位测试有能够引入的模块的途径有误,这里我们能够运用babel-plugin-module-resolver举行别号的替代

.babelrc

{
"presets": ["es2015"],
"plugins": [
["module-resolver", {
"root": ["./"],
"alias": {
"common":""
}
}]
]
}

运转效果

实行敕令

npm run test

如图
《怎样运用 mocha 和 sinon 集成单元测试--单元测试示例及剖析(上)》
《怎样运用 mocha 和 sinon 集成单元测试--单元测试示例及剖析(上)》
《怎样运用 mocha 和 sinon 集成单元测试--单元测试示例及剖析(上)》

最好实践总结

  • 文件名以及途径的定义以下,如许定义范例了途径的誊写,便于文件的查找

/a/b/c/demo.js //待测试文件
/tests/a/b/c/test.demo.js //单位测试文件

  • 一个单位测试文件测试一个js文件
  • 一个describe测试一个要领
  • 一个it 测试一个要领中一个逻辑,如许保证一个测试只考证一个行动
  • 运用sinon断绝外部挪用
  • 运用before或beforeEach 初始环境
  • 运用after或afterEach 清空或复原环境,差别单位测试互不影响,状况不同享

推荐阅读
  • Android实战——jsoup实现网络爬虫,糗事百科项目的起步
    本文介绍了Android实战中使用jsoup实现网络爬虫的方法,以糗事百科项目为例。对于初学者来说,数据源的缺乏是做项目的最大烦恼之一。本文讲述了如何使用网络爬虫获取数据,并以糗事百科作为练手项目。同时,提到了使用jsoup需要结合前端基础知识,以及如果学过JS的话可以更轻松地使用该框架。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 本文介绍了一些Java开发项目管理工具及其配置教程,包括团队协同工具worktil,版本管理工具GitLab,自动化构建工具Jenkins,项目管理工具Maven和Maven私服Nexus,以及Mybatis的安装和代码自动生成工具。提供了相关链接供读者参考。 ... [详细]
  • Node.js学习笔记(一)package.json及cnpm
    本文介绍了Node.js中包的概念,以及如何使用包来统一管理具有相互依赖关系的模块。同时还介绍了NPM(Node Package Manager)的基本介绍和使用方法,以及如何通过NPM下载第三方模块。 ... [详细]
  • 本文是一篇翻译文章,介绍了async/await的用法和特点。async关键字被放置在函数前面,意味着该函数总是返回一个promise。文章还提到了可以显式返回一个promise的方法。该特性使得async/await更易于理解和使用。本文还提到了一些可能的错误,并希望读者能够指正。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • 例如控件ID为user.id使用$(#user.id)不能得到正确的结果必须使用\\转义即$(#user\\.id)转载于:https:www.cnblogs.comrch ... [详细]
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
author-avatar
aaaa
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有