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相关推荐

  1. sinon.js基础使用教程---单元测试

    原文地址:www.sitepoint.com/sinon-tutor- 译文 当我们写单元测试时一个最大的绊脚石是当你面对的代码过于复杂. 在真实的项目中,我们的代码经常要做各种导致我们测试很难进行的 ...

  2. sinon.stub_JavaScript测试工具对决:Sinon.js vs testdouble.js

    sinon.stub 在对真实代码进行单元测试时,有许多情况使测试难以编写. 您如何检查是否调用了函数? 您如何测试Ajax呼叫? 还是使用setTimeout编码? 就是在这种情况下,您使用测试倍数 ...

  3. JavaScript测试工具对决:Sinon.js vs testdouble.js

    在对真实代码进行单元测试时,有许多情况使测试难以编写. 您如何检查是否调用了函数? 您如何测试Ajax呼叫? 还是使用setTimeout编码? 就是在这种情况下,您使用测试倍数 -替换代码使难以测试 ...

  4. Unit Testing with Sinon.JS

    Preface Which kind of method is the easiest to test? In my opinion, the answer is like this: 哪种方法最易于 ...

  5. 我为什么要写Sinon.JS

    2019独角兽企业重金招聘Python工程师标准>>> Good unit tests are focused, fast and isolated. Unfortunately, ...

  6. Sinon.JS Sinon.JS

    Sinon.JS Standalone test spies, stubs and mocks for JavaScript. No dependencies, works with any unit ...

  7. Stub和Mock的区别

    相同点:Stub和Mock对象都是用来模拟外部依赖,使我们能控制. 不同点:而stub完全是模拟一个外部依赖,用来提供测试时所需要的测试数据.而mock对象用来判断测试是否能通过,也就是用来验证测试中 ...

  8. 前端测试 -- sinon.js

    简介:sinon用于创建测试替身.消除测试环境复杂性 1.spies 2.stubs 完全替换目标函数.使得一个被stubbed的函数可以做任何你想要的(如抛出一个异常,返回某个特定值等) 创建: v ...

  9. 常规设置-Sinon.JS

    本文是个人对原文的翻译版,由于本人水平有限,如有理解上的错误,希望路过的大佬能指点一二,感激不尽. 正文: 在使用过程中,我们将会创建"伪造"(fakes),"间谍&qu ...

最新文章

  1. linux qt5.7下打地鼠源程序,基于QT的打地鼠游戏
  2. Android vector标签 PathData 画图超详解
  3. SQL Server 环形缓冲区(Ring Buffer) -- 介绍
  4. 蓝桥杯java最小公倍数_蓝桥杯算法训练 最大最小公倍数
  5. boost::math::quadrature::daubechies_wavelet_transform用法的测试程序
  6. Linux系统函数read()/write()/pread()/pwrite()的区别
  7. 阿里巴巴右侧6滑块VS雅虎右侧6滑块VS自定义6滑块
  8. php5中this_self_parent关键字用法讲解
  9. 如果你昨天刚离职却忘了退公司的群,转天一早领导找你让你尽快退群,你会做何感想呢?
  10. 频率主义(Frequentism)与贝叶斯主义(Bayesianism)的哲学辨异与实践(Python仿真)
  11. 使用PDF-XChange Editor为PDF文件添加图章(仅图片)
  12. 利用idea构建hibernate
  13. python基础版课件_Python入门基础ppt课件.ppt
  14. 用图片替代cursor光标样式
  15. oracle loap函数用法
  16. 点到直线的距离公式推导
  17. win10除去桌面图标小箭头(绝对没有坑!!!)与 该文件没有与之关联的程序来执行该操作。。。
  18. 【华为云】 搭建TFP站点心得体会
  19. 20221024-B站字幕的下载
  20. ORACLE删除归档日志和ORA-00257问题

热门文章

  1. 杨立昆怒怼机器人索菲娅:AI硬加人类意识是揠苗助长
  2. 计算机科学计算矩阵答案,计算机科学计算答案.doc
  3. 两阶提交、三阶提交、TCC框架
  4. 亿图图示--工业自动化模块--啤酒生产处理流程简图和热水冷凝处理架构
  5. 【KG】构建《红楼梦》知识图谱
  6. 《炬丰科技-半导体工艺》用湿法臭氧去除各种化学结构的聚合物
  7. Linux使用Geany开发gtk程序教程
  8. sklearn之逻辑回归LR
  9. android 远程视频监控程序源码,详解基于Android已开放源代码的远程视频监控系统教程...
  10. java广告排期系统_广告排期管理系统哪个好,或者有什么好的解决方案来管理排期?...