Sinon.JS 嘲笑混乱

Sinon.JS mocking confusion

我正在尝试学习如何使用 Sinon、Mocha 和 Chai 进行 JS 单元测试。现在,我想确认我的一个函数确实发出了 api 请求(所以我需要模拟我的函数)。我相信我已经在 Sinon 文档中找到了相关的模拟代码(它是用于测试 Ajax 的代码),但是,我无法理解发生了什么(文档非常稀疏)。谁能解释一下 it 函数中的 3 行代码(正下方)?

it("makes a GET request for todo items", function () {
  sinon.replace(jQuery, "ajax", sinon.fake());

  getTodos(42, sinon.fake());

  assert(jQuery.ajax.calledWithMatch({ url: "/todo/42/items" }));

供参考,被模拟的函数直接在下面:

function getTodos(listId, callback) {
  jQuery.ajax({
    url: "/todo/" + listId + "/items",
    success: function (data) {
      // Node-style CPS: callback(err, data)
      callback(null, data);
    },
  });
}

此外,这里有一个 link 文档: https://sinonjs.org/

让我们一步步来:

1。 sinon.replace(jQuery, "ajax", sinon.fake());

Sinon 创建了一个新的 fake 函数并用它替换了 jQuery.ajax 函数。

任何其他对 jQuery.ajax 的调用都会调用假的。默认情况下,假函数returns undefined,你也可以控制它;但这里不需要它(因为我们将断言它是否使用某些参数调用)。假函数与spies有相同的方法,所以假函数会像间谍一样记录有关其调用的信息。 (是否调用,参数等)

2。 getTodos(42, sinon.fake());

getTodos是测试的函数。这用 42 作为第一个参数和一个新的伪函数作为第二个参数(回调参数)调用它。

可能会传递一个假的,以防止使用实际回调的副作用。也可以放一个空函数来代替

getTodos(42, () => {});

回调函数与本次测试无关。它只需要 discarded/mocked.

3。 assert(jQuery.ajax.calledWithMatch({ url: "/todo/42/items" }));

断言检查表达式 jQuery.ajax.calledWithMatch({ url: "/todo/42/items" }) 是否为真。请记住,jQuery.ajax 被替换为假函数。因此,伪函数的 calledWithMatch 方法被调用。根据 calledWithMatch 的文档(在间谍部分):

spy.calledWithMatch(arg1, arg2, ...);
Returns true if spy was called with matching arguments (and possibly others).

This behaves the same as spy.calledWith(sinon.match(arg1), sinon.match(arg2), ...).

因此,如果使用匹配的参数(此处仅提供一个)调用假函数,它 returns 为真。 “匹配”行为是通过 matchers 定义的。这里使用对象匹配器(sinon.match(object)),匹配if

sinon.match(object);
Requires the value to be not null or undefined and have at least the same properties as expectation.

This supports nested matchers.

因此,此对象在 getTodo 中传递给 jQuery.ajax:

{
    url: "/todo/42/items",
    success: function (data) {
      callback(null, data);
    },
}

匹配

{ url: "/todo/42/items" }

根据对象匹配器定义。因此,此匹配器检查 jQuery.ajax 方法是否使用包含 url 属性 且值为 "/todo/42/items".

的对象调用

总结

  1. 首先我们模拟了 jQuery.ajax 因为我们不想发出实际请求,只是想检查它是否被调用。
  2. 我们调用 getTodos,这是我们的测试对象,带有 42 和一个伪造的回调参数。
  3. 我们希望 jQuery.ajax 被调用的对象 url 属性 的值为“/todo/42/items”。