sinon.js的spy、stub和mock
sinon
做测试的知道,在 Java 的单元测试中,不能获取实际对象时,我们可以使用 Mock/Stub 对我们的代码进行mock 等操作,更好的方便我们测试。
像 EasyMock、JMock、Mockito 等可以很好的解决这些事情。里面引入了 spy 、stub、mock等概念。
同样的,在前端测试中,我们也会遇到类似情况。Sinon.js 就是一个帮我们做这些事情的优秀库。
官网 : http://sinonjs.org/
Spy
翻译过来的意思是 “监视”,很贴切。
sinon.js 中 spy 主要用来监视函数的调用情况,sinon 对待监视的函数进行 wrap 包装,因此可以通过它清楚的知道,该函数被调用过几次,传入什么参数返回什么结果,甚至是抛出的异常情况。
看个例子:
var sinon = require('sinon');
var expect = require('chai').expect;var orginObj = {'launch': function() {console.log('I am launch function');}
}var myspy = sinon.spy(orginObj, 'launch');// 监视 orginObj.launch.console.log(typeof myspy);console.log('-------------')
// 调用 orginObj.launch
orginObj.launch('sss');// 函数调用次数
expect(orginObj.launch.callCount).to.be.equal(1)// 该函数以该参数调用过
expect(orginObj.launch.called).be.True;// 该函数以该参数调用过一次
expect(orginObj.launch.withArgs("sss").calledOnce).to.be.True;
从上面的例子可以看出,spy 确实给出了详细的函数被调用情况。那么 spy 到底是什么呢?首先发现它是个函数。
var myspy = sinon.spy(orginObj, 'launch');// 监视 orginObj.launch.
console.log(typeof myspy);// function
把这个函数对象打印出来如下:
{ [Function: proxy]isSinonProxy: true,formatters:{ c: [Function],n: [Function],D: [Function],C: [Function],t: [Function],'*': [Function] },reset: [Function],invoke: [Function: invoke],named: [Function: named],getCall: [Function: getCall],getCalls: [Function],calledBefore: [Function: calledBefore],calledAfter: [Function: calledAfter],calledImmediatelyBefore: [Function: calledImmediatelyBefore],calledImmediatelyAfter: [Function: calledImmediatelyAfter],withArgs: [Function],matchingFakes: [Function],matches: [Function],printf: [Function],calledOn: [Function],alwaysCalledOn: [Function],calledWith: [Function],calledWithMatch: [Function],alwaysCalledWith: [Function],alwaysCalledWithMatch: [Function],calledWithExactly: [Function],alwaysCalledWithExactly: [Function],neverCalledWith: [Function],neverCalledWithMatch: [Function],threw: [Function],alwaysThrew: [Function],returned: [Function],alwaysReturned: [Function],calledWithNew: [Function],alwaysCalledWithNew: [Function],callArg: [Function],callArgWith: [Function],callArgOn: [Function],callArgOnWith: [Function],throwArg: [Function],yield: [Function],invokeCallback: [Function],yieldOn: [Function],yieldTo: [Function],yieldToOn: [Function],spyCall: { [Function: createSpyCall] toString: [Function] },called: false,notCalled: true,calledOnce: false,calledTwice: false,calledThrice: false,callCount: 0,firstCall: null,secondCall: null,thirdCall: null,lastCall: null,args: [],returnValues: [],thisValues: [],exceptions: [],callIds: [],errorsWithCallStack: [],displayName: 'launch',toString: [Function: toString],instantiateFake: [Function: create],id: 'spy#0',stackTrace: 'Error: Stack Trace for original\n XXXXXXXXXXXXXX,restore: { [Function] sinon: true },wrappedMethod: [Function] }
里面包含一些基本的function 和 函数被调用情况 以及 stackTrace。
stub
在 Junit 中,我们有时候会使用stub 来嵌入或者直接替换掉一些代码,来达到隔离的目的。一个Stub可以使用最少的依赖方法来模拟该单元测试。比如一个方法可能依赖另一个方法的执行,而后者对我们来说是透明的。好的做法是使用stub 对它进行隔离替换。这样就实现了更准确的单元测试。
简单的说,stub是代码的一部分。在运行时用stub替换真正代码,忽略调用代码的原有实现。目的是用一个简单一点的行为替换一个复杂的行为,从而独立地测试代码的某一部分。
下面的例子能很好的看出这点:
// // 创建一个 stub
var stub = sinon.stub();var testObj = {'fun' : function (arg) {// ...},'secondFun' : function(arg){},'thirdFun': function (arg) {// body...}
}// // 将 testObj.fun 替换成一个stub,使用完毕后需要调用stub.restore() 或 testObj.fun.restore 复原。
var stub = sinon.stub(testObj, 'fun');// // 将testObj.fun 替换成指定的函数
// var stub = sinon.stub(testObj, "fun", function (argument) {
// // body...
// })
stub();
expect(stub.callCount).to.be.equal(1);// testObj.secondFun 替换成指定的函数,不建议使用,以后会废弃
var stub2 = sinon.stub(testObj, "secondFun", function (arg) {console.log('I am replaced function');
});stub2('arg');
expect(stub2.withArgs("arg").calledOnce).to.be.True;var stub3 = sinon.stub(testObj, "thirdFun").callsFake(function (arg) {console.log('I am replaced function3');
});stub3('arg');
expect(stub3.withArgs("arg").calledOnce).to.be.True;
这里要的注意两点:
1.我们要对 函数进行替换,当对一个没定义的函数进行替换会报错。
2. 对象的某个函数属性只能被 stub 一次。当尝试第二次 stub时会报错。
如果要在一个测试集里面多次stub 同一个函数,可以在钩子函数里面对其进行初始化。另外,由于 stub 是使用指定函数替换已有的函数,所以每次使用后最好复原它。做法很简单如下:
stub3.restore()
另外,stub 也可以用来改变函数的行为来完成我们特殊的测试用例。比如返回值、抛出异常等。有兴趣的同学可以自己尝试下。
// stub.returns(6666);
// stub(); // stub() 总是返回 6666// stub.throws('6666');// stub(); // stub() 总是抛出 '6666'// stub.withArgs(1).returns(6666);
// stub(1); // stub() 总是返回 6666
mock
一个对象被mock 后,我们就可以对它进行设定我们的预期,比如我们期望它最多最少被调用多少次,否是抛出异常等。
mock不实现任何逻辑,一切对 mock的调用都是假的。它更多的是用来测试对象的交互行为有没有发生,对象的交互有没有按照预期的进行。
var obj = {'fun': function (argument) {// body...}};var mock = sinon.mock(obj);// obj.fun(10) 至少被调用过 1 次
mock.expects('fun').atLeast(1).atMost(5).withArgs(10);
// mock.expects("method").once().throws();obj.fun(10);mock.verify();// 测试此时的 obj 是否满足上面的mock 设定条件。mock.restore();
比较
spy : 监视函数被调用情况。
stub : 替换对象的函数行为。
mock : 设定函数行为,并验证。
从这点来说,mock 更像是 spy 和 stub 的合体。看下面一个例子,这里我想测试 myPrinter,但是它的函数还没实现,先用 一个对象代替。
var orgin = {'print': function (prt) {console.log('I am print of orgin')}
}var myPrinter = {'getPrinter': function () {// TODO}
}var mocker = sinon.mock(orgin);// 由于我们的 printer 还没实现,先用 orgin 代替.这样我们就能测试 myPrinter 的方法了.
var stub4Printer = sinon.stub(myPrinter, "getPrinter").callsFake(function () {return orgin;
});// 此时测试还没执行,但我们预期 orgin的print() 将会被传入 'Hustzw' 作为参数调用一次
mocker.expects('print').once().withArgs('Hustzw');// 测试执行
stub4Printer().print('Hustzw');mocker.verify();// 验证 mocker 是否满足上面的mock 预期。
// 在完成执行测试后,我们的 print() 在测试过程中应该会被调用一次mocker.restore();
sinon.js的spy、stub和mock相关推荐
- sinon.js基础使用教程---单元测试
原文地址:www.sitepoint.com/sinon-tutor- 译文 当我们写单元测试时一个最大的绊脚石是当你面对的代码过于复杂. 在真实的项目中,我们的代码经常要做各种导致我们测试很难进行的 ...
- sinon.stub_JavaScript测试工具对决:Sinon.js vs testdouble.js
sinon.stub 在对真实代码进行单元测试时,有许多情况使测试难以编写. 您如何检查是否调用了函数? 您如何测试Ajax呼叫? 还是使用setTimeout编码? 就是在这种情况下,您使用测试倍数 ...
- JavaScript测试工具对决:Sinon.js vs testdouble.js
在对真实代码进行单元测试时,有许多情况使测试难以编写. 您如何检查是否调用了函数? 您如何测试Ajax呼叫? 还是使用setTimeout编码? 就是在这种情况下,您使用测试倍数 -替换代码使难以测试 ...
- Unit Testing with Sinon.JS
Preface Which kind of method is the easiest to test? In my opinion, the answer is like this: 哪种方法最易于 ...
- 我为什么要写Sinon.JS
2019独角兽企业重金招聘Python工程师标准>>> Good unit tests are focused, fast and isolated. Unfortunately, ...
- Sinon.JS Sinon.JS
Sinon.JS Standalone test spies, stubs and mocks for JavaScript. No dependencies, works with any unit ...
- Stub和Mock的区别
相同点:Stub和Mock对象都是用来模拟外部依赖,使我们能控制. 不同点:而stub完全是模拟一个外部依赖,用来提供测试时所需要的测试数据.而mock对象用来判断测试是否能通过,也就是用来验证测试中 ...
- 前端测试 -- sinon.js
简介:sinon用于创建测试替身.消除测试环境复杂性 1.spies 2.stubs 完全替换目标函数.使得一个被stubbed的函数可以做任何你想要的(如抛出一个异常,返回某个特定值等) 创建: v ...
- 常规设置-Sinon.JS
本文是个人对原文的翻译版,由于本人水平有限,如有理解上的错误,希望路过的大佬能指点一二,感激不尽. 正文: 在使用过程中,我们将会创建"伪造"(fakes),"间谍&qu ...
最新文章
- linux qt5.7下打地鼠源程序,基于QT的打地鼠游戏
- Android vector标签 PathData 画图超详解
- SQL Server 环形缓冲区(Ring Buffer) -- 介绍
- 蓝桥杯java最小公倍数_蓝桥杯算法训练 最大最小公倍数
- boost::math::quadrature::daubechies_wavelet_transform用法的测试程序
- Linux系统函数read()/write()/pread()/pwrite()的区别
- 阿里巴巴右侧6滑块VS雅虎右侧6滑块VS自定义6滑块
- php5中this_self_parent关键字用法讲解
- 如果你昨天刚离职却忘了退公司的群,转天一早领导找你让你尽快退群,你会做何感想呢?
- 频率主义(Frequentism)与贝叶斯主义(Bayesianism)的哲学辨异与实践(Python仿真)
- 使用PDF-XChange Editor为PDF文件添加图章(仅图片)
- 利用idea构建hibernate
- python基础版课件_Python入门基础ppt课件.ppt
- 用图片替代cursor光标样式
- oracle loap函数用法
- 点到直线的距离公式推导
- win10除去桌面图标小箭头(绝对没有坑!!!)与 该文件没有与之关联的程序来执行该操作。。。
- 【华为云】 搭建TFP站点心得体会
- 20221024-B站字幕的下载
- ORACLE删除归档日志和ORA-00257问题
热门文章
- 杨立昆怒怼机器人索菲娅:AI硬加人类意识是揠苗助长
- 计算机科学计算矩阵答案,计算机科学计算答案.doc
- 两阶提交、三阶提交、TCC框架
- 亿图图示--工业自动化模块--啤酒生产处理流程简图和热水冷凝处理架构
- 【KG】构建《红楼梦》知识图谱
- 《炬丰科技-半导体工艺》用湿法臭氧去除各种化学结构的聚合物
- Linux使用Geany开发gtk程序教程
- sklearn之逻辑回归LR
- android 远程视频监控程序源码,详解基于Android已开放源代码的远程视频监控系统教程...
- java广告排期系统_广告排期管理系统哪个好,或者有什么好的解决方案来管理排期?...