准备条件
以第1节教程的创建的目录和代码为基础进行讲解。如果没有看过第1节教程,请关注我,查看以往该系列的文章
这节教程主要讲解jest中的mock函数,将第1节的代码复制一份,并且把index.js
和index.test.js
文件内容全部清空
mock函数可以在你测试实际代码的时候,捕获对函数的调用以及参数和返回值等,也可以用于模拟一些数据
安装axios
npm run axios --save
在 index.js
中写入一些待测试方法
import axios from 'axios'
export function callbackFun(fn) {
return fn()
}
export function getData() {
// 这里接口路径随便写一个就可以
return axios.get('/api').then(res => res.data)
}
使用mock
在 index.test.js
中写入1个测试实例
import { callbackFun, getData } from './index'
test('测试 callbackFun,使用mockReturnValueOnce设置返回值', () => {
let fun = jest.fn()
fun.mockReturnValueOnce('123') // 设置调用函数1次的返回值
fun.mockReturnValueOnce('456') // 设置调用函数2次的返回值
fun.mockReturnValue('666') //设置每次调用函数的值都为666
expect(callbackFun(fun)).toBe('123')
expect(callbackFun(fun)).toBe('456')
expect(callbackFun(fun)).toBe('666')
expect(callbackFun(fun)).toBe('666')
console.log(fun.mock)
})
- 这里
jest.fn()
这里使用jest模拟一个函数,可以传入一个函数生成带逻辑的函数 .mockReturnValueOnce()
设置调用一次函数的返回值,设置几个就是几次.mockReturnValue()
设置调用函数的返回值.mock
每个jest生成的函数都有mock属性,里面包含里一下几个属性
在 index.test.js
中再写入1个测试实例
test('测试 callbackFun,使用mockImplementation设置返回值', () => {
let fun = jest.fn()
// 设置调用函数1次的返回值
fun.mockImplementationOnce(() => {
return '123'
})
//设置每次调用函数的值都为666
fun.mockImplementation(() => {
return '666'
})
expect(callbackFun(fun)).toBe('123')
expect(callbackFun(fun)).toBe('666')
expect(callbackFun(fun)).toBe('666')
})
- 这里的
mockImplementationOnce
和mockReturnValueOnce
功能一样,设置一次函数的返回值,只不过更强大一些,可以在函数里面写更多的逻辑 mockImplementation
和mockReturnValue
功能一样,设置每次函数的返回值,功能更强大一些
上面知道了jest.fn()中有个mock属性,可以通过这个属性内的值来造一些事情
在 index.test.js
中再写入1个测试实例
test('测试 callbackFun,使用mock属性测试', () => {
let fun = jest.fn()
fun.mockReturnValueOnce('123')
fun.mockReturnValue('666')
let obj = {}
callbackFun(fun.bind(obj))
callbackFun(fun)
expect(fun).toBeCalled() // 测试函数fun是否被调用
expect(fun.mock.calls.length).toBe(2) // 测试函数是否被调用两次
expect(fun.mock.instances[0]).toEqual(obj) // 测试第一次调用this是否是obj
expect(fun.mock.calls[0][0]).toBeUndefined() //测试第一次调用函数参数是否为空
console.log(fun.mock)
})
这里学习的小伙伴可以打印下mock,对照的理解
使用mock模拟接口数据
实际开发项目中,测试接口我们不能直接请求接口,最好的方式还是模拟个mock数据
// 这两句加在测试文件头部
import axios from 'axios'
jest.mock('axios')
test('测试 getData,使用mock', async() => {
// 模拟第一次接收到的数据
axios.get.mockResolvedValueOnce({
data: '123'
})
// 模拟每一次接收到的数据
axios.get.mockResolvedValue({
data: '456'
})
const data1 = await getData()
const data2 = await getData()
expect(data1).toBe('123')
expect(data2).toBe('456')
})
jest.mock('axios')
模拟axios请求数据,不会发送真实请求(改变了axios函数内部实现) 这样写我们就不会真的去请求后台接口数据了,而是使用我们自己的数据结构
将模拟异步数据代码提出
这样写已经解决了问题,但是我们想更优雅的写代码,模拟的数据写在测试实例里面总是不太好,所以jest还给我们提供了另一种方法
- 将
index.test.js
内容删除 - 根目录新建
__mocks__
文件夹,在里面新建index.js
并在写入一下内容
// 返回一个promise
export function getData() {
return new Promise(resolve => {
resolve({
data: '测试数据'
})
})
}
- 在
index.test.js
中写入以下测试用例
jest.mock('./index') // 设置使用mock文件
import { getData } from './index' //会去__mocks__文件夹中寻找
// 设置callbackFun方法从源文件index中查找
const { callbackFun } = jest.requireActual('./index')
test('测试 getData,使用__mock__', async () => {
const data = await getData()
expect(data).toEqual({ data: '测试数据' })
})
test('测试 callbackFun,使用mockReturnValueOnce设置返回值', () => {
let fun = jest.fn()
fun.mockReturnValueOnce('123')
expect(callbackFun(fun)).toBe('123')
})
这样我们就成功将异步的数据拿到外面了,这里需要注意几点
jest.mock('./index')
会设置自动从__mocks__文件中找文件- 设置后import拿的文件就是__mocks__中的,但是我们还需要测试其他方法,因此需要设置
const { callbackFun } = jest.requireActual('./index')
,从原本的index.js文件中找到方法,否则会提示callbackFun找不到
这节教程逻辑有些复杂,一定要自己动手试一下
下一节教程将介绍在jest中怎样去对定时器测试
本人能力有限,文章可能会有不正确或者不恰当的部分,希望你可以指出