My-Note-Blog icon indicating copy to clipboard operation
My-Note-Blog copied to clipboard

jest mock

Open huangchucai opened this issue 6 years ago • 0 comments

jest mock讲解

jest.fn()

创建:jest 创建mock最简单的方法就是直接使用jest.fn() 使用

  1. jest.fn接受一个callback当做函数真正的调用,如果没有函数内部的实现,会默认的返回undefined
  2. 会返回一个mock属性,来展示mock函数的一些调用情况

用途:

  1. 跟踪函数的调用情况(this, 返回值,参数)

  2. 判定一个回调函数是否被执行(一般用途)

创建一个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()

用途:

  1. 改变模块的默认一些实现
  2. mock整个模块

改变模块的内部实现

上一个我们创建了一个demo.js文件中,有一个异步获取接口数据的getData方法,在单元测试的时候,我们不能每一个接口都发送异步请求,想想,那如果在集成测试的时候,几百个接口,我们需要等待的时间太长了,所以想通过mock来获取数据。

  1. 通过jest.mock('axios'),让jest在执行的时候,优先执行mock的内容
  2. 执行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');
        });
    });
});

  1. 使用jest.mock()的时候,会默认的提升到文件第一行
  2. 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

huangchucai avatar Aug 21 '19 03:08 huangchucai