stubs 什么时候使用存根?

用存根包装现有函数时,不会调用原始函数。它支持syp的所有API
当您要执行以下操作时,请使用存根:

  1. 从测试中控制方法的行为,以强制代码沿特定路径移动。示例包括强制方法抛出错误以测试错误处理。
  2. 当您要防止直接调用特定方法时(可能是因为它触发了不希望的行为,例如a XMLHttpRequest或类似行为)。

https://sinonjs.org/releases/v7.5.0/stubs/
可以指定参数个数,指定参数调用函数,指定对象的属性的get,set,value,

  1. const assert = require('assert').strict;
  2. const sinon = require("sinon");
  3. debugger;
  4. let obj = {
  5. methodA: function () {
  6. console.log("objA methodA");
  7. },
  8. name: 'obj'
  9. };
  10. let objA = {
  11. methodA: function () {
  12. console.log("objA methodA");
  13. }
  14. };
  15. let objB = {
  16. methodA: function () {
  17. console.log("objB methodA");
  18. }
  19. };
  20. let objC = function () {
  21. this.name = 'objC';
  22. this.foo = '999';
  23. console.log("objC methodA");
  24. }
  25. let objD = function () {
  26. this.name = 'objD';
  27. this.foo = '999';
  28. console.log("objD methodA");
  29. }
  30. let stub = sinon.stub(); // 返回一个空的监听方法,可以监听通话,sinon.stub具有sinon.spy的所有API
  31. let stub2 = sinon.stub(objA, "methodA"); // 监听这个方法
  32. let stub3 = sinon.stub(objB, 'methodA').callsFake(function () { // 替换原方法
  33. console.log("stub3")
  34. });
  35. // objB.method.restore(); stub3.restore(); 可以恢复原方法
  36. let stub4 = sinon.stub(obj); // 监听整个对象
  37. stub2();
  38. stub3();
  39. // let stub4 = sinon.createStubInstance(objC, {
  40. // foo: sinon.stub().returnsThis()
  41. // }); // 如果不想调用sinon.stub构造函数来创建可以通过此语句创建sinon.createStubInstance(MyConstructor, overrides);
  42. // /* 上一条语句与下面语句等同
  43. // let stub = sinon.createStubInstance(MyConstructor);
  44. // stub.foo.returnsThis();
  45. // */
  46. // let stub = sinon.createStubInstance(objD, {
  47. // foo: 3
  48. // });
  49. // /*上一条语句与下面语句等同
  50. // let stub = sinon.createStubInstance(MyConstructor);
  51. // stub.foo.returns(3);
  52. // */
  53. describe("stubs", function () {
  54. before("before", function () {
  55. });
  56. it("测试", function () {
  57. let callback = sinon.stub();
  58. callback.withArgs(42).returns(1);
  59. callback.withArgs(1).throws("name");
  60. assert(callback() === undefined); // No return value, no exception
  61. assert(callback(42) === 1); // Returns 1
  62. assert.throws(function () {
  63. callback(1)
  64. }, {
  65. message: '',
  66. name: 'name'
  67. },
  68. '不是期望的错误');
  69. })
  70. it("return ", async function () {
  71. this.timeout(0);
  72. let callback = sinon.stub();
  73. callback.onCall(0).returns(1); // 设置第一次调用返回
  74. callback.onCall(1).returns(2); // 设置第二次调用返回
  75. callback.returns(3); // 其他调用返回
  76. callback(); // Returns 1
  77. callback(); // Returns 2
  78. callback(); // All following calls return 3
  79. callback.withArgs(42) // 如果参数是42的话
  80. .onFirstCall().returns(1) // 如果参数是42的话,第一次返回
  81. .onSecondCall().returns(2); // 如果参数是42的话,第一次返回
  82. callback.returns(0); // 其他返回
  83. callback(1); // Returns 0
  84. callback(42); // Returns 1
  85. callback(1); // Returns 0
  86. callback(42); // Returns 2
  87. callback(1); // Returns 0
  88. callback(42); // Returns 0
  89. callback.returnsArg(0); // callback.returnsArg(index); 传入1时,参数必须是两个, 使用索引处的参数作为返回值
  90. // 要求调用callback时必须传入固定数量的参数, 莫名其妙的api和文档的说明不符
  91. let a = callback(9, 1); // 调用后返回1
  92. let returns = callback.returnsThis(); // 这里返回stub的实例 api的作用是使存根返回其this值。
  93. callback.resetBehavior();
  94. let callback2 = sinon.stub();
  95. let promise = callback2.resolves(1) // 返回一个promise的实例
  96. let promiseValue = await promise(); // 1
  97. callback2.resolvesArg(1); // 表示要2个参数才可以,参数必须是两个, 使用索引处的参数作为返回值
  98. promise = callback2.resolves(2); // 返回一个promise的实例
  99. promise = await promise(1, 2) // 结果为2,必须传入两个参数
  100. console.log(promise)
  101. /*
  102. stub.onFirstCall();
  103. 别名 stub.onCall(0);
  104. stub.onSecondCall();
  105. 别名 stub.onCall(1);
  106. stub.onThirdCall();
  107. 别名 stub.onCall(2);
  108. stub.reset();
  109. 重置存根的行为和历史记录。
  110. 这等效于同时调用stub.resetBehavior()和stub.resetHistory()
  111. 更新于 sinon@2.0.0
  112. 以来 sinon@5.0.0
  113. 为方便起见,您可以stub.reset()使用sinon.reset()
  114. */
  115. callback.resetBehavior(); // 将存根的行为重置为默认行为
  116. let stubB = sinon.stub();
  117. stubB.returns(54)
  118. stubB(); // 54
  119. stubB.resetBehavior();
  120. stubB(); // undefined
  121. assert(typeof Promise === 'function');
  122. let stubC = sinon.stub();
  123. stubC.throwsArg(3); // 规定要多少个参数 数量是index + 1, 使用索引处的参数作为返回值,抛出异常, 但是会被stubC.throws();覆盖
  124. assert.throws(function () {
  125. stubC(1, 2, 3, 4);
  126. }, 4);
  127. stubC.throws(); // 使存根引发异常(Error)。
  128. stubC.throws("name"/*[, "message"]*/); // 使存根引发异常,并将name属性设置为提供的字符串。message参数是可选的,它将设置message异常的属性。
  129. // stubC.throws({ name: 'exp', message: "exp" }); // 使存根引发提供的异常对象。
  130. stubC.throws(function () { return new Error("stubC"); }); // 使存根引发该函数返回的异常。
  131. assert.throws(function () {
  132. stubC(1, 2, 3, 4);
  133. }, Error("stubC"),
  134. '不是期望的错误');
  135. stubC.resetBehavior()
  136. let promise4 = stubC.rejects();
  137. try {
  138. promise4 = await promise4();
  139. } catch (err) {
  140. err;
  141. }
  142. promise4 = stubC.rejects("TypeError");
  143. try {
  144. promise4 = await promise4();
  145. } catch (err) {
  146. err;
  147. }
  148. promise4 = stubC.rejects("sss");
  149. try {
  150. promise4 = await promise4();
  151. } catch (err) {
  152. err; // 抛出 message: sss的异常
  153. }
  154. // stub.rejects(); 使存根返回一个Promise,该Promise会被拒绝(例外)(Error)。
  155. // stub.rejects("TypeError"); 使存根返回一个Promise,该Promise拒绝提供的类型除外。
  156. // stub.rejects(value); 抛出异常
  157. });
  158. it("return 2", function () {
  159. var objCD = {};
  160. objCD.sum = function sum (a, b) {
  161. return a + b;
  162. };
  163. sinon.stub(objCD, 'sum');
  164. objCD.sum.withArgs(2, 2).callsFake(function foo () {
  165. return 'bar';
  166. });
  167. objCD.sum.callThrough(); // 当没有条件存根匹配时,导致调用包装到存根中的原始方法。
  168. assert(objCD.sum(2, 2) === 'bar'); // 'bar'
  169. assert(objCD.sum(1, 2) === 3); // 3
  170. var objAB = {};
  171. objAB.Sum = function MyConstructor (a, b) {
  172. this.result = a + b();
  173. };
  174. var re = function () { return 2 }
  175. sinon
  176. .stub(objAB, 'Sum')
  177. .callThroughWithNew() // 使用new语法
  178. .callsArg(1) // 使存根调用提供的索引处的参数作为回调函数。
  179. .withArgs(1, re)
  180. .returns({ result: 9000 });
  181. try {
  182. new objAB.Sum(2, 2);
  183. } catch (err) {
  184. err; // "argument at index 1 is not a function: 2"
  185. }
  186. assert((new objAB.Sum(2, re)).result === 4); // 4
  187. assert((new objAB.Sum(1, re)).result === 9000); // 9000
  188. });
  189. });

stub.callsArgOn(index, context);

像,stub.callsArg(index);但带有附加参数来传递this上下文。

stub.callsArgWith(index, arg1, arg2, ...);

类似于callsArg,但带有传递给回调的参数。

stub.callsArgOnWith(index, context, arg1, arg2, ...);

像上面一样,但是带有附加参数来传递this上下文。

stub.usingPromise(promiseLibrary);

使用stub.rejects或时,使存根使用特定的Promise库而不是全局库返回Promise stub.resolves。返回存根以允许链接。

  1. var myObj = {
  2. saveSomething: sinon.stub().usingPromise(bluebird.Promise).resolves("baz");
  3. }
  4. myObj.saveSomething()
  5. .tap(function(actual) {
  6. console.log(actual); // baz
  7. });

以来 sinon@2.0.0

stub.yields([arg1, arg2, ...])

类似于callsArg
使存根使用提供的参数(如果有)调用它收到的第一个回调。
如果一个方法接受多个回调,则需要使用yieldsRight来调用最后一个回调或callsArg使存根调用除第一个或最后一个回调以外的其他回调。

stub.yieldsRight([arg1, arg2, ...])

喜欢,yields但调用它收到的最后一个回调。

stub.yieldsOn(context, [arg1, arg2, ...])

像,yields但带有附加参数来传递this上下文。

stub.yieldsTo(property, [arg1, arg2, ...])

使间谍程序调用作为对象属性传递给间谍程序的回调。
像一样yieldsyieldsTo获取第一个匹配的参数,找到回调并使用(可选)参数调用它。

stub.yieldsToOn(property, context, [arg1, arg2, ...])

像上面一样,但是带有附加参数来传递this上下文。

  1. "test should fake successful ajax request": function () {
  2. sinon.stub(jQuery, "ajax").yieldsTo("success", [1, 2, 3]);
  3. jQuery.ajax({
  4. success: function (data) {
  5. assertEquals([1, 2, 3], data);
  6. }
  7. });
  8. }

stub.yield([arg1, arg2, ...])

stub使用给定参数调用传递给的回调。
如果从未使用函数参数调用存根,yield则会引发错误。
返回一个Array,如果没有引发错误,则所有回调均按调用顺序返回值。
也别名为invokeCallback

stub.yieldTo(callback, [arg1, arg2, ...])

调用作为对象属性传递给存根的回调。
像一样yieldyieldTo获取第一个匹配的参数,找到回调并使用(可选)参数调用它。

  1. "calling callbacks": function () {
  2. var callback = sinon.stub();
  3. callback({
  4. "success": function () {
  5. console.log("Success!");
  6. },
  7. "failure": function () {
  8. console.log("Oh noes!");
  9. }
  10. });
  11. callback.yieldTo("failure"); // Logs "Oh noes!"
  12. }

stub.callArg(argNum)

与相似yield,但有一个明确的参数编号指定要调用的回调。
如果通过多个回调函数调用函数,并且不需要简单地调用第一个回调函数,则很有用。

  1. "calling the last callback": function () {
  2. var callback = sinon.stub();
  3. callback(function () {
  4. console.log("Success!");
  5. }, function () {
  6. console.log("Oh noes!");
  7. });
  8. callback.callArg(1); // Logs "Oh noes!"
  9. }

stub.callArgWith(argNum, [arg1, arg2, ...])

类似于callArg,但带有参数。

异步呼叫

与它们对应的非异步对象相同,但是在处理完当前调用堆栈中的所有指令后,将在调用时延迟回调。

  • 在Node环境中,回调使用延迟process.nextTick
  • 在浏览器中,回调是通过延迟的setTimeout(callback, 0)

更多信息: