Skip to main content

模拟模块

模块可以分为两种模块:

  • 第三方模块。
  • 文件模块。

模拟第三方模块

假设现在项目中有如下的一个方法,现在需要对这个模块的方法进行一个测试,此时会涉及到一个问题,要测试这个模块就必然会涉及到使用axios发送真实的http请求,这个时候就要屏蔽这个真实的请求。

const axios = require('axios')

function getUsers() {
return new Promise(async (resolve) => {
try {
const res = await axios.get('/users.json')
resolve(res.data)
} catch (e) {
reject(e)
}
})
}

要解决这个问题,大概有两种方式:

  1. 模拟一个getUsers函数,屏蔽内部的实现,但这种方式无法测试该方法内部的实现是否正确。
  2. 模拟axios模块来屏蔽axios发送请求这个部分。

使用jest.mock来模拟axios这个模块:

const axios = require('axios')
const useData = require('./users.json')

// 模拟 axios 模块
jest.mock('axios')

test('Fetch user data', async () => {
const res = {
data: useData
}

axios.get.mockImplementation(() => Promise.resolve(res))

await expect(getUsers()).resolves.toEqual(useData)
})

如上的的测试套件中,首先使用jest.mock方法模拟了axios这个模块。在测试用例里面,指定了axios.get方法的行为,之后对getUsers方法进行测试,在该方法里面使用到axios.get 方法,这个时候就会使用模拟的axios模块。

jest.mock也可传入第二个参数,该参数是一个工厂函数,可以指定模块的一些实现:

const axios = require('axios')
const useData = require('./users.json')

jest.mock('axios', () => {
const userData = require('./users.json')

const resp = {
data: userData
}

return {
get: jest.fn(() => Promise.resolve(resp))
}
})

test('Fetch user data', async () => {
await expect(getUsers()).resolves.toEqual(useData)
})

模拟本地模块

通过jest.mock,还可以模拟整个本地模块:

const modulePath = './tools.js'
const { sum, sub, mul, div } = require(modulePath)

jest.mock(modulePath, () => {
const originalModule = jest.requireActual(modulePath)

return {
...originalModule,
sum: jest.fn(() => 100),
sub: jest.fn(() => 50)
}
})

test('test local module', () => {
expect(sum(1, 2)).toBe(100)
expect(sub(10, 2)).toBe(50)
expect(mul(6, 8)).toBe(48)
expect(div(100, 4)).toBe(25)
})