2021-11-09 單元測試之sinon的入門

測試輔助工具 Sinon

Sinon 是用來輔助我們進行前端測試的,在我們的代碼需要與其他系統或者函數對接時,它可以模擬這些場景,從而使我們測試的時候不再依賴這些場景。
Sinon 有主要有三個方法輔助我們進行測試:spystubmock

Sinon 的安裝

在講解用法前,先看一下我們的測試項目結構:

然後這裏的測試例子用的是官網上的例子,once.js 的內容是:

export default function once(fn) {
  var returnValue,
    called = false;
  return function () {
    if (!called) {
      called = true;
      returnValue = fn.apply(this, arguments);
    }
    return returnValue;
  };
}

once.test.js 的內容爲空。

那麼接着安裝 Sinon

npm install --save-dev sinon

Sinon 之 spy

官方對 spy 的解釋:A test spy is a function that records arguments, return value, the value of this and exception thrown (if any) for all its calls. There are two types of spies: Some are anonymous functions, while others wrap methods that already exist in the system under test.

spy 生成一個間諜函數,它會記錄下函數調用的參數,返回值,this 的值,以及拋出的異常。
spy 一般有兩種玩法,一種是生成一個新的匿名間諜函數,另外一種是對原有的函數進行封裝並進行監聽。

搭好上面的結構後,直接在 once.test.js 裏面寫入 spy 的使用例子:

import { assert } from "chai";
import sinon from "sinon";
import once from "../src/once";

describe("測試Once函數", function () {
  it("傳入Once的函數會被調用", function () {
    var callback = sinon.spy();
    var proxy = once(callback);

    proxy();

    assert(callback.called);
  });
});

如上面代碼所示,sinon.spy() 會產生一個函數對象,當 once 調用這個函數對象後,這個函數對象通過 called 可以返回一個 bool 值,表示函數是否被調用。

測試結果爲:

現在來看看 spy 的另一種玩法,即對原有函數的監控玩法,在 once.test.js 中加入以下測試用例:

it("對原有函數的spy封裝,可以監聽原有函數的調用情況", function () {
  const obj = {
    func: () => {
      return 1 + 1;
    },
  };
  sinon.spy(obj, "func");

  obj.func(3);

  assert(obj.func.calledOnce);
  assert.equal(obj.func.getCall(0).args[0], 3);
});

測試結果:

更多 spy 的 API 請參考

Sinon 之 Stub

來看看 Stub 的官方介紹:Test stubs are functions (spies) with pre-programmed behavior.
They support the full test spy API in addition to methods which can be used to alter the stub’s behavior.
As spies, stubs can be either anonymous, or wrap existing functions. When wrapping an existing function with a stub, the original function is not called.

stub 是帶有預編程行爲的函數。
簡單點說,就是 spy 的加強版,不僅完全支持 spy 的各種操作,還能操作函數的行爲。
spy 一樣,stub 也能匿名,也能去封住並監聽已有函數。
然而有一點和 spy 不同,當封裝了一個已有函數後,原函數不會再被調用。

對於匿名的玩法我們就不說了,直接來封裝的玩法,以下是對之前 spy 封裝的修改:

it("對原有函數的stub封裝,可以監聽原有函數的調用情況,以及模擬返回", function () {
  const obj = {
    func: () => {
      console.info(1);
    },
  };
  sinon.stub(obj, "func").returns(42);

  const result = obj.func(3);

  assert(obj.func.calledOnce);
  assert.equal(obj.func.getCall(0).args[0], 3);
  assert.equal(result, 43);
});

測試結果如下:

根據測試結果可以瞭解到,原函數 func 的內容確實沒有被執行,因爲沒有打印 1。

更多 API 查看 Sinon 之 stub

Sinon 之 mock

看一下官網的介紹:Mocks (and mock expectations) are fake methods (like spies) with pre-programmed behavior (like stubs) as well as pre-programmed expectations.
A mock will fail your test if it is not used as expected.

大致意思就是 mockspystub 一樣的僞裝方法,如果 mock 沒有得到期望的結果就會測試失敗。

這裏的話可能講述不是很清楚,那麼看一下代碼就很好理解了:

it("mock的測試", function () {
  var myAPI = {
    method: function () {
      console.info("運行method");
    },
    func: function () {
      console.info("運行method");
    },
  };

  var mock = sinon.mock(myAPI);
  mock.expects("method").once().returns(2);
  mock.expects("func").twice();

  myAPI.method();
  myAPI.func();
  myAPI.func();

  mock.verify();
});

在以上代碼中,mock 其實和 stub 很像,只不過是 stub 是對對象中單個函數的監聽和攔截,而 mock 是對多個。
mock 首先會對函數進行一個預期:

var mock = sinon.mock(myAPI);
mock.expects("method").once().returns(2);
mock.expects("func").twice();

比如 once 就是預期運行一次,如果最終驗證時函數沒有被執行或者執行多次都會拋出錯誤。
也可以操作返回結果,比如像 stub 一樣 returns(2) 依然有效。
而且與 stub 一樣,在 mock 監聽後,原有函數內容將不會執行。

在進行了預期操作後,就對函數進行實際操作:

myAPI.method();
myAPI.func();
myAPI.func();

最後再進行驗證操作

mock.verify();

運行上述測試用例得到以下結果

小結

Sinon 主要是一個測試輔助工具,通過僞裝和攔截,來模擬與其他系統或函數的操作,可以解耦測試的依賴。
在上面只講到了 Sinon 的 spystubmock 三個函數,其實還有 fake XHR(模擬 xhr 請求)、fack server(模擬服務器)以及 fake timer(模擬定時器)等操作。

作者:韓子盧
出處:https://www.cnblogs.com/vvjiang/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章