- 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的所有API
let 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 exception
assert(callback(42) === 1); // Returns 1
assert.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 1
callback(); // Returns 2
callback(); // All following calls return 3
callback.withArgs(42) // 如果参数是42的话
.onFirstCall().returns(1) // 如果参数是42的话,第一次返回
.onSecondCall().returns(2); // 如果参数是42的话,第一次返回
callback.returns(0); // 其他返回
callback(1); // Returns 0
callback(42); // Returns 1
callback(1); // Returns 0
callback(42); // Returns 2
callback(1); // Returns 0
callback(42); // Returns 0
callback.returnsArg(0); // callback.returnsArg(index); 传入1时,参数必须是两个, 使用索引处的参数作为返回值
// 要求调用callback时必须传入固定数量的参数, 莫名其妙的api和文档的说明不符
let a = callback(9, 1); // 调用后返回1
let returns = callback.returnsThis(); // 这里返回stub的实例 该api的作用是使存根返回其this值。
callback.resetBehavior();
let callback2 = sinon.stub();
let promise = callback2.resolves(1) // 返回一个promise的实例
let promiseValue = await promise(); // 1
callback2.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(); // 54
stubB.resetBehavior();
stubB(); // undefined
assert(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); // 3
var 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); // 4
assert((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'