一、為什么需要引入mock?
最常見的回調函數就是ajax請求,返回數據后執行成功或失敗的回調。在Node 環境下,有一個npm 包request, 它可以發送異步請求,返回數據后調用回調函數進行處理,npm i request --save, 安裝一下,然后func.js 修改如下
const request = require('request'); function fetchData(callback) { request('https://jsonplaceholder.typicode.com/todos/1', function (error, response, body) { callback(body); }); } module.exports = fetchData;
那怎么測試?肯定調用fetchData, 那就先要創建一個回調函數傳給它,因為fetchData獲取到數據后,會調用回調函數,那就可以在回調函數中創建一個斷言,判斷返回的數據是不是和期望的一樣。func.test.js 文件修改為如下測試代碼。
const fetchData = require('./fun'); test('should return data when fetchData request success', () => { function callback(data) { expect(data).toEqual({ "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false }) } fetchData(callback); })
執行npm run test 命令,看到pass,但其實並沒有達到預期的效果,在callback 函數中加入console.log(data) 試一試,就知道了。測試文件改變后,jest 會重新跑一遍(開啟了watch),但並沒有打印出data,也就是說callback 函數並沒有被調用。這是為什么,我在這個地方想了好久,主要還是對異步了解的不夠。當執行jest 測試的時候,實際上是node 執行test函數體的代碼,首先看到callback的函數聲明,它聲明函數,然后看到fetchData() ,它就調用這個函數,請求https://jsonplaceholder.typicode.com/todos/1 接口,這個時候,getTodo函數就執行完了。你可能會想,回調函數都沒有執行,這個函數怎么算執行完了呢?回調函數並不是代碼執行的,而是放到node的異步隊列中被執行的。此時我們就必須引入mock函數了。
二、Jest中的Mock Function
(1)、在jest 創建一個Mock 函數最簡單的方法就是調用jest.fn() 方法。創建mock函數來捕獲調用。具體實現如下:
demo.js文件代碼:
export const forEach = (items, callback) =>{ for (let index = 0; index < items.length; index++) { callback(items[index]); } }
對應的測試用例代碼:demo.test.js
import {forEach} from "./demo"; test('forEach',()=>{ const mockCallback = jest.fn(); forEach([0, 1], mockCallback); console.log('mockCallback',mockCallback.mock)//為此mock 函數還有一個mock 屬性 expect(mockCallback.mock.calls.length).toBe(2) })
實現結果如下:
calls 保存的就是調用狀態,results保存的就是返回值。invocationCallOrder數組表示函數調用順序。instances表示當前的this
(2)、mockReturnValue 和 mockReturnValueOnce 設置函數的返回值。
import {forEach} from "./demo"; test('forEach',()=>{ const mockCallback = jest.fn(); mockCallback.mockReturnValueOnce('abs') forEach([0, 1], mockCallback); console.log('mockCallback',mockCallback.mock) expect(mockCallback.mock.calls.length).toBe(2) })
運行結果如下:
mockReturnValueOnce 修改成 mockReturnValue之后發現返回的value值都變成abs。mock函數有mockReturnValue(),它的參數就是返回值。不過它不能返回promise. 可以使用mockResolvedValue直接返回promise的值. 對fetchData 進行mock, 然后設置它的mockResolvedValue()
(3)、toHaveBeenCalled(), toHaveBeenCalledTimes() ,使用起來有點方便了。你可能見過toBeCalled(), 其實,它和toHaveBeenCalled() 功能是一模一樣的,使用哪個都行。使用起來非常方便。
import {forEach} from "./demo";
test('forEach',()=>{
const mockCallback = jest.fn();
mockCallback.mockReturnValueOnce('abs')
forEach([0, 1], mockCallback);
console.log('mockCallback',mockCallback.mock)
//expect(mockCallback.mock.calls.length).toBe(2)
expect(mockCallback).toHaveBeenCalled()
})