在项目中,一个模块的方法内常常会去调用另外一个模块的方法。在单元测试中,我们可能并不需要关心内部调用的方法的执行过程和结果,
只想知道它是否被正确调用即可,甚至会指定该函数的返回值
。此时,使用Mock函数是十分有必要。
jest
对象上有
fn,mock,spyOn
三个方法,在实际项目的单元测试中,
jest.fn()
常被用来进行某些有回调函数的测试;
jest.mock()
可以
mock
整个模块中的方法,当某个模块已经被单元测试100%覆盖时,使用
jest.mock()
去
mock
该模块,节约测试时间和测试的冗余度是十分必要;当需要测试某些必须被完整执行的方法时,常常需要使用
jest.spyOn()
。
Jest.fn()
jest.fn()
是创建
Mock
函数最简单的方式,如果没有定义函数内部的实现,
jest.fn()
会返回
undefined
作为返回值。
test('测试jest.fn()调用', () => {
let mockFn = jest.fn();
let result = mockFn(1, 2, 3);
expect(result).toBeUndefined();
expect(mockFn).toBeCalled();
expect(mockFn).toBeCalledTimes(1);
expect(mockFn).toHaveBeenCalledWith(1, 2, 3);
jest.fn()
所创建的Mock函数还可以设置返回值,定义内部实现或返回Promise
对象。
test('测试jest.fn()返回固定值', () => {
let mockFn = jest.fn().mockReturnValue('default');
expect(mockFn()).toBe('default');
test('测试jest.fn()内部实现', () => {
let mockFn = jest.fn((num1, num2) => {
return num1 * num2;
expect(mockFn(10, 10)).toBe(100);
test('测试jest.fn()返回Promise', async () => {
let mockFn = jest.fn().mockResolvedValue('default');
let result = await mockFn();
expect(result).toBe('default');
expect(Object.prototype.toString.call(mockFn())).toBe("[object Promise]");
下面我们在src/fetch.js
文件中写一些被测试代码,以更加接近业务的方式来理解Mock函数的实际应用。
被测试代码中依赖了axios
这个常用的请求库和JSONPlaceholder
请求接口,请先在shell
中执行npm install axios --save
安装依赖,。
const axios = require('axios');
async function fetchPostsList(callback) {
return axios.get('https://jsonplaceholder.typicode.com/posts').then(res => {
return callback(res.data);
module.exports = fetchPostsList;
我们在fetch.js
中封装了一个fetchPostsList
方法,该方法请求了JSONPlaceholder
提供的接口,并通过传入的回调函数返回处理过的返回值。如果我们想测试该接口能够被正常请求,只需要捕获到传入的回调函数能够被正常的调用即可。下面是functions.test.js
中的测试的代码。
const fetch = require('../src/fetch');
test('fetchPostsList callback was called', async () => {
expect.assertions(1);
let mockFn = jest.fn();
await fetch(mockFn);
expect(mockFn).toBeCalled();
.mock
属性
所有的 mock
函数都有一个特殊的 .mock
属性,它保存了关于此函数如何被调用、调用时的返回值的信息。
test('test function forEach', () => {
const mockCallback = jest.fn(x => 88 + x);
forEach([0, 1], mockCallback);
expect(mockCallback.mock.calls.length).toBe(2);
expect(mockCallback.mock.calls[0][0]).toBe(0);
expect(mockCallback.mock.calls[1][0]).toBe(1);
expect(mockCallback.mock.results[0].value).toBe(88);
expect(mockCallback.mock.results[1].value).toBe(89);
Jest.mock()
通常情况下,我们需要调用api,发送ajax请求,从后台获取数据。但是我们在做前端测试的时候,并不需要去调用真实的接口,所以此时我们需要模拟 axios/fetch
模块,让它不必调用api也能测试我们的接口调用是否正确。
const fetch = require('./fetch');
async function getPostList() {
return fetch(data => {
console.log('fetchPostsLits be called');
module.exports = getPostList;
测试代码如下:
const fetch = require('../src/fetch');
const event = require('../src/event');
jest.mock('../src/fetch.js');
test('fetchPostsList callback was called', async () => {
expect.assertions(1);
let mockFn = jest.fn();
await fetch(mockFn);
expect(mockFn).toBeCalled();