深入理解Jest中的mock

對於異步函數的測試,Jest中封裝了獨立的API,通過例子整理分類如下。

1.模擬請求

目錄結構:

|--demo.js
|--demo.test.js
|--package-lock.json
|--package.json
|--node_modules
|--.babelrc

業務代碼:demo.js

import axios from 'axios'

export const fetchData = () => {
	return axios.get('/').then(res => res.data)
}

測試代碼:demo.test.js

import { fetchData } from './demo'
import Axios from 'axios'
jest.mock('axios') // 模擬axios

test('fetchData 測試', () => {
	// 模擬請求
	Axios.get.mockResolvedValue({
		data: "(function(){return '123'})()"
	})
	return fetchData().then(data => {
		expect(eval(data)).toEqual('123');
	})
})

2.模擬demo

在根目錄下新建一個模擬文件夾,名字爲__mocks__,在__mocks__文件夾下新建demo.js文件。

|--__mocks__
	|--demo.js
|--demo.js
|--demo.test.js
|--package-lock.json
|--package.json
|--node_modules
|--.babelrc

情景:當我們測試發送異步請求的代碼時,我們可以直接通過模擬demo的方式,測試請求方法是否正常執行.
demo.js

import axios from 'axios'

export const fetchData = () => {
	// 發異步請求
	return axios.get('/').then(res => res.data)
}

_ mocks _/demo.js

export const fetchData = () => {
	// 做假請求
	return new Promise((resolved, reject) => {
		resolved("(function(){return '123'})()")
	})
}

demo.test.js

jest.mock('./demo'); // 使用jest模擬demo,當執行測試用例時,就會去__mocks__文件下去找demo.js
import { fetchData } from './demo' // 通過jest模擬demo之後,再通過import引入fetchData
// 這裏引的fetchData是我們模擬的fetchData
test('fetchData 測試', () => {
	return fetchData().then(data => {
		expect(eval(data)).toEqual('123')
	})
})

3.自動模擬設置

目錄結構和代碼同模擬demo一致。
通過修改jest.config.js配置,讓其自動模擬進行測試.
首先, 在命令行執行 npx jest --init 讓jest的配置文件暴露出來. 把配置文件中的自動模擬項(automock)設置爲true.

然後: 把demo.test.js文件中的 jest.mock(’./demo’) 刪除掉.

import { fetchData } from './demo'

test('fetchData 測試', () => {
	return fetchData().then(data => {
		expect(eval(data)).toEqual('123')
	})
})

此時,再執行 npm test ,測試用例依然會通過。

注: 當我們把配置項 automock 修改爲 true 後,jest就會開啓自動模擬功能,就算測試文件中沒有聲明模擬代碼,jest依然會去自動查找根目錄中是否有mocks文件的存在,mocks文件夾下是否有相對應的demo.js文件。如果有,那麼在使用 import { fetchData } from ‘./demo’ 引入demo時,會拿mocks下的demo代替我們寫的業務代碼demo被引入。如果沒有,則會引入根目錄下得我們寫的業務文件demo。這就是自動模擬的運行機制。

4.異步函數模擬—同步函數不模擬

目錄結構:

|--__mocks__
	|--demo.js
|--demo.js
|--demo.test.js
|--package-lock.json
|--package.json
|--node_modules
|--.babelrc

demo.js

import axios from 'axios'

// 異步函數
export const fetchData = () => {
	// 發異步請求
	return axios.get('/').then(res => res.data)
}

// 同步函數
export const getNumber = () => {
	return 123;
}

demo.test.js

jest.mock('./demo'); // 使用jest模擬demo,當執行測試用例時,就會去__mocks__文件下去找demo.js
import { fetchData } from './demo'; // 通過jest模擬demo,這裏的fetchData是來自於模擬的demo裏的
const { getNumber } = jest.requireActual('./demo'); // 這裏的getNumber是來自於真正的demo裏的

test('fetchData 測試', () => {
	return fetchData().then(data => {
		expect(eval(data)).toEqual('123');
	})
})

test('getNumber 測試', () => {
	expect(getNumber()).toBe(123);
})
  • jest.requireActual(’./demo’) 引入真正的業務代碼文件。(不是通過jest模擬的)
  • 對異步函數模擬、對同步函數不模擬,這樣既可實現同步函數 和 異步函數的完美測試。

取消模擬

jest.unmock('./demo'); // 取消模擬demo
jest.unmock('axios'); // 取消模擬axios
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章