- 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)
- 跳過這個測試
- 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");