- stubs 什么时候使用存根?
stub.callsArgOn(index, context);stub.callsArgWith(index, arg1, arg2, ...);stub.callsArgOnWith(index, context, arg1, arg2, ...);stub.usingPromise(promiseLibrary);stub.yields([arg1, arg2, ...])stub.yieldsRight([arg1, arg2, ...])stub.yieldsOn(context, [arg1, arg2, ...])stub.yieldsTo(property, [arg1, arg2, ...])stub.yieldsToOn(property, context, [arg1, arg2, ...])stub.yield([arg1, arg2, ...])stub.yieldTo(callback, [arg1, arg2, ...])stub.callArg(argNum)stub.callArgWith(argNum, [arg1, arg2, ...])- 异步呼叫
stub.callsArgAsync(index);stub.callsArgOnAsync(index, context);stub.callsArgWithAsync(index, arg1, arg2, ...);stub.callsArgOnWithAsync(index, context, arg1, arg2, ...);stub.yieldsAsync([arg1, arg2, ...]);stub.yieldsOnAsync(context, [arg1, arg2, ...]);stub.yieldsToAsync(property, [arg1, arg2, ...]);stub.yieldsToOnAsync(property, context, [arg1, arg2, ...])
sinon.addBehavior(name, fn);stub.get(getterFn)stub.set(setterFn)stub.value(newVal)
stubs 什么时候使用存根?
用存根包装现有函数时,不会调用原始函数。它支持syp的所有API
当您要执行以下操作时,请使用存根:
- 从测试中控制方法的行为,以强制代码沿特定路径移动。示例包括强制方法抛出错误以测试错误处理。
- 当您要防止直接调用特定方法时(可能是因为它触发了不希望的行为,例如a XMLHttpRequest或类似行为)。
https://sinonjs.org/releases/v7.5.0/stubs/
可以指定参数个数,指定参数调用函数,指定对象的属性的get,set,value,
const assert = require('assert').strict;const sinon = require("sinon");debugger;let obj = {methodA: function () {console.log("objA methodA");},name: 'obj'};let objA = {methodA: function () {console.log("objA methodA");}};let objB = {methodA: function () {console.log("objB methodA");}};let objC = function () {this.name = 'objC';this.foo = '999';console.log("objC methodA");}let objD = function () {this.name = 'objD';this.foo = '999';console.log("objD methodA");}let stub = sinon.stub(); // 返回一个空的监听方法,可以监听通话,sinon.stub具有sinon.spy的所有APIlet stub2 = sinon.stub(objA, "methodA"); // 监听这个方法let stub3 = sinon.stub(objB, 'methodA').callsFake(function () { // 替换原方法console.log("stub3")});// objB.method.restore(); stub3.restore(); 可以恢复原方法let stub4 = sinon.stub(obj); // 监听整个对象stub2();stub3();// let stub4 = sinon.createStubInstance(objC, {// foo: sinon.stub().returnsThis()// }); // 如果不想调用sinon.stub构造函数来创建可以通过此语句创建sinon.createStubInstance(MyConstructor, overrides);// /* 上一条语句与下面语句等同// let stub = sinon.createStubInstance(MyConstructor);// stub.foo.returnsThis();// */// let stub = sinon.createStubInstance(objD, {// foo: 3// });// /*上一条语句与下面语句等同// let stub = sinon.createStubInstance(MyConstructor);// stub.foo.returns(3);// */describe("stubs", function () {before("before", function () {});it("测试", function () {let callback = sinon.stub();callback.withArgs(42).returns(1);callback.withArgs(1).throws("name");assert(callback() === undefined); // No return value, no exceptionassert(callback(42) === 1); // Returns 1assert.throws(function () {callback(1)}, {message: '',name: 'name'},'不是期望的错误');})it("return ", async function () {this.timeout(0);let callback = sinon.stub();callback.onCall(0).returns(1); // 设置第一次调用返回callback.onCall(1).returns(2); // 设置第二次调用返回callback.returns(3); // 其他调用返回callback(); // Returns 1callback(); // Returns 2callback(); // All following calls return 3callback.withArgs(42) // 如果参数是42的话.onFirstCall().returns(1) // 如果参数是42的话,第一次返回.onSecondCall().returns(2); // 如果参数是42的话,第一次返回callback.returns(0); // 其他返回callback(1); // Returns 0callback(42); // Returns 1callback(1); // Returns 0callback(42); // Returns 2callback(1); // Returns 0callback(42); // Returns 0callback.returnsArg(0); // callback.returnsArg(index); 传入1时,参数必须是两个, 使用索引处的参数作为返回值// 要求调用callback时必须传入固定数量的参数, 莫名其妙的api和文档的说明不符let a = callback(9, 1); // 调用后返回1let returns = callback.returnsThis(); // 这里返回stub的实例 该api的作用是使存根返回其this值。callback.resetBehavior();let callback2 = sinon.stub();let promise = callback2.resolves(1) // 返回一个promise的实例let promiseValue = await promise(); // 1callback2.resolvesArg(1); // 表示要2个参数才可以,参数必须是两个, 使用索引处的参数作为返回值promise = callback2.resolves(2); // 返回一个promise的实例promise = await promise(1, 2) // 结果为2,必须传入两个参数console.log(promise)/*stub.onFirstCall();别名 stub.onCall(0);stub.onSecondCall();别名 stub.onCall(1);stub.onThirdCall();别名 stub.onCall(2);stub.reset();重置存根的行为和历史记录。这等效于同时调用stub.resetBehavior()和stub.resetHistory()更新于 sinon@2.0.0以来 sinon@5.0.0为方便起见,您可以stub.reset()使用sinon.reset()*/callback.resetBehavior(); // 将存根的行为重置为默认行为let stubB = sinon.stub();stubB.returns(54)stubB(); // 54stubB.resetBehavior();stubB(); // undefinedassert(typeof Promise === 'function');let stubC = sinon.stub();stubC.throwsArg(3); // 规定要多少个参数 数量是index + 1, 使用索引处的参数作为返回值,抛出异常, 但是会被stubC.throws();覆盖assert.throws(function () {stubC(1, 2, 3, 4);}, 4);stubC.throws(); // 使存根引发异常(Error)。stubC.throws("name"/*[, "message"]*/); // 使存根引发异常,并将name属性设置为提供的字符串。message参数是可选的,它将设置message异常的属性。// stubC.throws({ name: 'exp', message: "exp" }); // 使存根引发提供的异常对象。stubC.throws(function () { return new Error("stubC"); }); // 使存根引发该函数返回的异常。assert.throws(function () {stubC(1, 2, 3, 4);}, Error("stubC"),'不是期望的错误');stubC.resetBehavior()let promise4 = stubC.rejects();try {promise4 = await promise4();} catch (err) {err;}promise4 = stubC.rejects("TypeError");try {promise4 = await promise4();} catch (err) {err;}promise4 = stubC.rejects("sss");try {promise4 = await promise4();} catch (err) {err; // 抛出 message: sss的异常}// stub.rejects(); 使存根返回一个Promise,该Promise会被拒绝(例外)(Error)。// stub.rejects("TypeError"); 使存根返回一个Promise,该Promise拒绝提供的类型除外。// stub.rejects(value); 抛出异常});it("return 2", function () {var objCD = {};objCD.sum = function sum (a, b) {return a + b;};sinon.stub(objCD, 'sum');objCD.sum.withArgs(2, 2).callsFake(function foo () {return 'bar';});objCD.sum.callThrough(); // 当没有条件存根匹配时,导致调用包装到存根中的原始方法。assert(objCD.sum(2, 2) === 'bar'); // 'bar'assert(objCD.sum(1, 2) === 3); // 3var objAB = {};objAB.Sum = function MyConstructor (a, b) {this.result = a + b();};var re = function () { return 2 }sinon.stub(objAB, 'Sum').callThroughWithNew() // 使用new语法.callsArg(1) // 使存根调用提供的索引处的参数作为回调函数。.withArgs(1, re).returns({ result: 9000 });try {new objAB.Sum(2, 2);} catch (err) {err; // "argument at index 1 is not a function: 2"}assert((new objAB.Sum(2, re)).result === 4); // 4assert((new objAB.Sum(1, re)).result === 9000); // 9000});});
stub.callsArgOn(index, context);
像,stub.callsArg(index);但带有附加参数来传递this上下文。
stub.callsArgWith(index, arg1, arg2, ...);
stub.callsArgOnWith(index, context, arg1, arg2, ...);
stub.usingPromise(promiseLibrary);
使用stub.rejects或时,使存根使用特定的Promise库而不是全局库返回Promise stub.resolves。返回存根以允许链接。
var myObj = {saveSomething: sinon.stub().usingPromise(bluebird.Promise).resolves("baz");}myObj.saveSomething().tap(function(actual) {console.log(actual); // baz});
stub.yields([arg1, arg2, ...])
类似于callsArg。
使存根使用提供的参数(如果有)调用它收到的第一个回调。
如果一个方法接受多个回调,则需要使用yieldsRight来调用最后一个回调或callsArg使存根调用除第一个或最后一个回调以外的其他回调。
stub.yieldsRight([arg1, arg2, ...])
stub.yieldsOn(context, [arg1, arg2, ...])
stub.yieldsTo(property, [arg1, arg2, ...])
使间谍程序调用作为对象属性传递给间谍程序的回调。
像一样yields,yieldsTo获取第一个匹配的参数,找到回调并使用(可选)参数调用它。
stub.yieldsToOn(property, context, [arg1, arg2, ...])
像上面一样,但是带有附加参数来传递this上下文。
"test should fake successful ajax request": function () {sinon.stub(jQuery, "ajax").yieldsTo("success", [1, 2, 3]);jQuery.ajax({success: function (data) {assertEquals([1, 2, 3], data);}});}
stub.yield([arg1, arg2, ...])
stub使用给定参数调用传递给的回调。
如果从未使用函数参数调用存根,yield则会引发错误。
返回一个Array,如果没有引发错误,则所有回调均按调用顺序返回值。
也别名为invokeCallback。
stub.yieldTo(callback, [arg1, arg2, ...])
调用作为对象属性传递给存根的回调。
像一样yield,yieldTo获取第一个匹配的参数,找到回调并使用(可选)参数调用它。
"calling callbacks": function () {var callback = sinon.stub();callback({"success": function () {console.log("Success!");},"failure": function () {console.log("Oh noes!");}});callback.yieldTo("failure"); // Logs "Oh noes!"}
stub.callArg(argNum)
与相似yield,但有一个明确的参数编号指定要调用的回调。
如果通过多个回调函数调用函数,并且不需要简单地调用第一个回调函数,则很有用。
"calling the last callback": function () {var callback = sinon.stub();callback(function () {console.log("Success!");}, function () {console.log("Oh noes!");});callback.callArg(1); // Logs "Oh noes!"}
stub.callArgWith(argNum, [arg1, arg2, ...])
异步呼叫
与它们对应的非异步对象相同,但是在处理完当前调用堆栈中的所有指令后,将在调用时延迟回调。
- 在Node环境中,回调使用延迟
process.nextTick。 - 在浏览器中,回调是通过延迟的
setTimeout(callback, 0)。
更多信息:
- https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick,
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/EventLoop,
- https://developer.mozilla.org/zh-CN/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout。
stub.callsArg(index)的异步版本。另请参见异步调用。stub.callsArgAsync(index);
stub.callsArgOn(index,context)的异步版本。另请参见异步调用。stub.callsArgOnAsync(index, context);
stub.callsArgWith(index,arg1,arg2,…)的异步版本。另请参见异步调用。stub.callsArgWithAsync(index, arg1, arg2, ...);
stub.callsArgOnWith(index,context,arg1,arg2,…)的异步版本。另请参见异步调用。stub.callsArgOnWithAsync(index, context, arg1, arg2, ...);
stub.yields([arg1,arg2,…])的异步版本。另请参见异步调用。stub.yieldsAsync([arg1, arg2, ...]);
stub.yieldsOn(context,[arg1,arg2,…])的异步版本。另请参见异步调用。stub.yieldsOnAsync(context, [arg1, arg2, ...]);
stub.yieldsTo(property,[arg1,arg2,…])的异步版本。另请参见异步调用。stub.yieldsToAsync(property, [arg1, arg2, ...]);
stub.yieldsToOn(property,context,[arg1,arg2,…])的异步版本。另请参见异步调用。stub.yieldsToOnAsync(property, context, [arg1, arg2, ...])
添加自定义行为。该名称将在存根上作为函数提供,并且将为您建立链接机制(例如,无需从函数中返回任何内容,其返回值将被忽略)。该sinon.addBehavior(name, fn);fn会通过假实例作为其第一个参数,然后将用户的论点。const sinon = require('sinon');sinon.addBehavior('returnsNum', (fake, n) => fake.returns(n));var stub = sinon.stub().returnsNum(42);assert.equals(stub(), 42);
替换此存根的新getter。stub.get(getterFn)var myObj = { prop: 'foo' }; sinon.stub(myObj, 'prop').get(function getterFn() { return 'bar'; }); myObj.prop; // 'bar'
为此存根定义一个新的setter。stub.set(setterFn)var myObj = { example: 'oldValue', prop: 'foo' }; sinon.stub(myObj, 'prop').set(function setterFn(val) { myObj.example = val; }); myObj.prop = 'baz'; myObj.example; // 'baz'
为此存根定义一个新值。stub.value(newVal)
您可以通过调用var myObj = { example: 'oldValue', }; sinon.stub(myObj, 'example').value('newValue'); myObj.example; // 'newValue'restore方法来恢复值:var myObj = { example: 'oldValue', }; var stub = sinon.stub(myObj, 'example').value('newValue'); stub.restore() myObj.example; // 'oldValue'
