My-Note-Blog
My-Note-Blog copied to clipboard
jest mock
jest mock讲解
jest.fn()
创建:jest 创建mock最简单的方法就是直接使用jest.fn()
使用:
- jest.fn接受一个callback当做函数真正的调用,如果没有函数内部的实现,会默认的返回undefined
- 会返回一个
mock属性,来展示mock函数的一些调用情况
用途:
-
跟踪函数的调用情况(this, 返回值,参数)
-
判定一个回调函数是否被执行(一般用途)
创建一个demo.js
import axios from 'axios';
export const getData = () => {
return axios.get('https://jsonplaceholder.typicode.com/todos/1').then(res => {
return res.data;
});
};
// callBack调用
export const runCallback = (callback) => {
callback('abc');
};
export const add = (a, b) => {
return a + b;
};
创建一个demo.test.js
import { runCallback } from './demo';
describe('单元测试笔记', () => {
test('jest fn函数mock', () => {
const mockFn = jest.fn();
// 没有内部实现的时候返回undefined
expect(mockFn()).toBeUndefined();
runCallback(mockFn); // mockFn被回调函数执行, 会在mockFn上挂在一个mock属性,方便我们跟踪函数的调用
mockFn.mockReturnValue(2); // mock函数的调用值
expect(mockFn()).toBe(2);
expect(mockFn).toBeCalled(); // mock函数被执行
console.log(mockFn.mock);
});
});
Jest.mock()
用途:
- 改变模块的默认一些实现
- mock整个模块
改变模块的内部实现
上一个我们创建了一个demo.js文件中,有一个异步获取接口数据的getData方法,在单元测试的时候,我们不能每一个接口都发送异步请求,想想,那如果在集成测试的时候,几百个接口,我们需要等待的时间太长了,所以想通过mock来获取数据。
- 通过
jest.mock('axios'),让jest在执行的时候,优先执行mock的内容 - 执行
test()的时候,发现重写了axios.get,就会默认执行自己写的内容
jest.mock('axios');
import axios from 'axios';
import { getData } from './demo';
describe('单元测试笔记', () => {
test('测试ajax', () => {
axios.get.mockResolvedValue({data: 'hello world'});
return getData().then(res => {
expect(res).toBe('hello world');
});
});
});
mock整个模块
在文件的所在的目录下创建一个__mocks__文件夹,大小写铭感,然后创建一个我们想要mock的文件名,目录结构如下:
├── README.md
├── __mocks__
│ └── demo.js
├── babel.config.js
├── demo.js
├── demo.test.js
├── jest.config.js
├── package-lock.json
└── package.json
jest.mock('./demo');
import { getData } from './demo';
describe('单元测试笔记', () => {
test('测试ajax', () => {
return getData().then(res => {
expect(res).toBe('hello world');
});
});
});
- 使用
jest.mock()的时候,会默认的提升到文件第一行 - jest在使用
demo的时候,会自动查找同级目录的__mocks__文件夹是否有同名的文件,如果有就覆盖文件中所有的内容
弊端
使用jest.mock()来模拟文件的时候,会mock覆盖整个文件,有时候我们只需要mock一部分,而不是全部覆盖。
我们在demo.js中我们增加一个功能函数add,如果我们按照上一个mock后的语法,来测试现在这个新增的add方法,就会出现报错add is not function
export const add = (a, b) => {
return a + b;
};
// demo.test.js
jest.mock('./demo');
import { getData, add } from './demo';
describe('单元测试笔记', () => {
test('测试ajax', () => {
return getData().then(res => {
expect(res).toBe('12');
});
});
test('add', () => {
expect(add(1, 2)).toBe(3);
});
});
# Error (0 , _demo.add) is not a function
# 告诉jest使用demo中add函数的时候,require真实demo中的函数,而不是用mock中的
import {getData} from './demo';
const {add} = jest.requireActual('./demo');
jest.spy()
本质上看jest.spy()是jest.fn()的一个语法糖,创建了一个和被spy(监听)的函数具有相同内部代码的mock函数。(相当于创建了一个mock函数,但是原函数还是会被调用)
返回值是一个mock函数,方便我们追踪函数的调用情况,但是jest.spy()只是监听函数的调用,并不会覆盖原函数的实现,原函数还是会被执行。一般使用过后,使用mockRestore重置mock函数
# demo.js
import axios from 'axios';
export const getData = () => {
console.log('执行getData');
return axios.get('https://jsonplaceholder.typicode.com/todos/1').then(res => {
return res.data;
});
};
export const add = (a, b) => {
return a + b;
};
#demo.test.js
import * as demo from './demo';
describe('单元测试笔记', () => {
test('spy function', async () => {
const spy = jest.spyOn(demo, 'getData');
const data = await spy();
console.log(data);
expect(spy).toBeCalled();
spy.mockRestore();
});
});
# 输出
执行getData
{
userId: 1,
id: 1,
title: 'delectus aut autem',
completed: false
}
如果我们想要覆盖掉原函数的实现,可以使用mockImplementation
import * as demo from './demo';
describe('单元测试笔记', () => {
test('spy function', async () => {
const spy = jest.spyOn(demo, 'getData').mockImplementation(() => 'spy');
const data = spy();
console.log(data);
expect(spy).toBeCalled();
spy.mockRestore();
});
});
# 输出
spy