Elaine's Blog 朝著 senior 前進的工程師

Jest 學習筆記

2018-09-15

  • Jest
    • Jest 是 Facebook 開源的一個前端測試框架
    • 主要用於 React 和 React Native 的單元測試,已被集成在 create-react-app 中

globals api

  • describe(name, fn) * 測試套件(test suite),講一組功能相關的測試用例組合在一起
  • it(name, fn, timeout) _ 別名 test,測試用例(test case),最小測試單位,要確保每一次測試的事件是單一的 _ test.only(name, fn, timeout) * 只執行一次
    • test.skip(name, fn)
      • 跳過這個測試
  • 周期函數
    • afterAll(fn, timeout) * 所有測試用例跑完以後執行的函數
    • beforeAll(fn, timeout) * 所有測試用例執行之前執行的函數
    • afterEach(fn) * 在每個測試用例執行完後執行的函數
    • beforeEach(fn) * 在每個測試用例執行之前需要執行的函數

全局和 describe 都可以有上面四個周期函數 describe 的 after 函數優先級要高於全局的 after 函數 describe 的 before 函數優先級要低於全局的 before 函數

Jest 對象

  • jest.fn(implementation)
    • 返回一個全新沒有使用過的 mock function,這個 function 在被調用的時候會記錄很多和函數調用有關的信息
  • jest.mock(moduleName, factory, options)
    • 用來 mock 一些模塊或者文檔
  • jest.spyOn(object, methodName)
    • 返回一個 mock function,和 jest.fn 相似,但是能夠追蹤 object[methodName] 的調用信息,類似 Sinon
  • jest.resetModules()
    • 確保 import/require 的 module 是初始乾淨未被污染的狀況
  • jest.resetAllMocks()
    • 重設所有 mock 物件的狀態

snapshot 快照

  • toMatchSnapshot 會產生 UI 結構,並用字串的形式存放在 __snapshots__ 檔案中
  • 通過比較兩個字串來判斷 UI 是否改變,因為是字串比較,所以性能很高
  • jest 在執行的時候如果發現 toMatchSnapshot 函數,會在同級目錄下生成一個 __snapshots__ 用來存放快照文檔,以後每次測試的時候都會和第一次生成的快照進行比較
  • 可以使用 jest –updateSnapshot 來更新快照文檔

常見斷言

  • expect(value) * 要測試一個值進行斷言的時候,要使用 expect 對值進行包裹
  • toBe(value) * 使用 Object.is 來進行比較,如果進行浮點數的比較,要使用 toBeCloseTo
  • not
    • 用來取反
  • toEqual(value) * 用於對象的深比較
  • toMatch(regexpOrString) * 用來檢查字符串是否匹配,可以是正則表達式或者字符串
  • toContain(item) * 用來判斷 item 是否在一個數組中,也可以用於字串的判斷
  • toBeNull(value) * 只匹配 null
  • toBeUndefined(value) * 只匹配 undefined
  • toBeDefined(value) * 與 toBeUndefined 相反
  • toBeTruthy(value) * 匹配任何使 if 語句為真的值
  • toBeFalsy(value) * 匹配任何使 if 語句為假的值
  • toBeGreaterThan(number) * 大於
  • toBeGreaterThanOrEqual(number) * 大於等於
  • toBeLessThan(number) * 小於
  • toBeLessThanOrEqual(number) * 小於等於
  • toBeInstanceOf(class) * 判斷是不是 class 的實例
  • anything(value) * 匹配除了 null 和 undefined 以外的所有值
  • resolves * 用來取出 promise 為 fulfilled 時包裹的值,支持鏈式調用
  • rejects * 用來取出 promise 為 rejected 時包裹的值,支持鏈式調用
  • toHaveBeenCalled()
    • 又名 toBeCalled() * 用來判斷 mock function 是否被調用過
  • toHaveBeenCalledTimes(number) * 用來判斷 mock function 被調用的次數
  • assertions(number) * 驗證在一個測試用例中有 number 個斷言被調用
  • extend(matchers) * 自定義一些斷言

mock

mock 一個函數

  • 使用 jest.fn() 就可以簡單 mock 一個 function

例如: 我們有一個函數叫做 forEach,這個函數的作用是取出陣列每個元素作為調用 callback 的參數,要如何測試此函數?

function forEach(items, call) {
  for (let index = 0; index < items.length; index++) {
    callback(items[index]);
  }
}

宣告一個 mock function

const mockCallback = jest.fn();

呼叫 forEach 並代入參數

forEach([0, 1], mockCallback);

斷言

// 此 mock function 被調用了兩次
expect(mockCallback.mock.calls.length).toBe(2);
// 第一次調用 mockCallback 函數時,第一個參數是 0
expect(mockCallback.mock.calls[0][0]).toBe(0);
// 第二次調用 mockCallback 函數時,第一個參數是 1
expect(mockCallback.mock.calls[1][0]).toBe(1);
  • mockCallback.mock.calls[0][0]
    • 第一個 index 是第幾次呼叫,第二個 index 是第幾個參數

mock function 的回傳值

  • 利用 mockReturnValue 來設定回傳值
const myMock = jest.fn();
myMock
  .mockReturnValueOnce(10) // 一次 return 值為 10
  .mockReturnValueOnce("x") // 一次 return 值為 'x'
  .mockReturnValue(true); // return 值為 true

console.log(myMock(), myMock(), myMock(), myMock());
// > 10, 'x', true, true

mock function 內容

一開始就設定好內容

const myMockFn = jest.fn(cb => cb(null, true));

myMockFn((err, val) => console.log(val));
// > true

myMockFn((err, val) => console.log(val));
// > true

如果宣告完之後,還想設定內容,可以利用 mockImplementation

const myMockFn = jest.fn();
myMockFn.mockImplementation(cb => cb(null, true));

如果你只想要他執行一次也可以用 mockImplementationOnce

const myMockFn = jest
  .fn()
  .mockImplementationOnce(cb => cb(null, true))
  .mockImplementationOnce(cb => cb(null, false));

myMockFn((err, val) => console.log(val));
// > true

myMockFn((err, val) => console.log(val));
// > false

mock 名字

可以使用 mockName 來給 mock 函式命名 如果沒有命名,輸出的日誌預設就會列印 jest.fn(),加上名字更有利於除錯

const myMockFn = jest
  .fn()
  .mockReturnValue("default")
  .mockImplementation(scalar => 42 + scalar)
  .mockName("add42");

mock module

使用 jest.mock 自動 mock

jest.mock("./moduleName");

參考資料


Similar Posts

上一篇 單元測試

Content