前端自动化测试jest教程6-mock函数

4,998 阅读4分钟

准备条件

以第1节教程的创建的目录和代码为基础进行讲解。如果没有看过第1节教程,请关注我,查看以往该系列的文章

这节教程主要讲解jest中的mock函数,将第1节的代码复制一份,并且把index.jsindex.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')
})
  • 这里的mockImplementationOncemockReturnValueOnce功能一样,设置一次函数的返回值,只不过更强大一些,可以在函数里面写更多的逻辑
  • mockImplementationmockReturnValue功能一样,设置每次函数的返回值,功能更强大一些

上面知道了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中怎样去对定时器测试

本人能力有限,文章可能会有不正确或者不恰当的部分,希望你可以指出

关注公众号,和我一起学习前端必备技能,前端自动化测试jest