(八)Jest测试的mock函数
一、为什么需要引入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()
})