(九)mock深入学习
1、前端如果测试接口请求返回值的时,可以请求服务器吗?
我们可以试着举个例子:
新建一个mocktest.js文件 import axios from 'axios' export const fetchData=()=>{ return axios.get('/').then(res=>res.data) } 新建一个mocktest.test.js文件: import {fetchData} from './mocktest' test('测试fetchData',()=>{ return fetchData().then(data=>{ expect(eval(data)).toEqual('12') }) })
运行结果如下:
很显然异步函数请求服务器是无法连接成功的。此时我们就需要模拟请求。
2、模拟请求
接着上个示例,借助 mockResolvedValue 函数,修改如下:
import {fetchData} from './mocktest' import Axios from 'axios' jest.mock('axios') // mock模拟ajax 反向的是jest.unmock('axios') test('fetchData 测试', () => { // 模拟请求 不会真正的请求接口,替代异步请求 Axios.get.mockResolvedValue({ data: "(function(){return '12'})()" }) return fetchData().then(data => { expect(eval(data)).toEqual('12'); }) })
修改完成之后,继续运行测试用例,可以正常运行。
3、模拟demo
在根目录下新建一个模拟文件夹,名字为__mocks__,在__mocks__文件夹下新建demo.js文件。
__mocks__/mocktest.js
export const fetchData=()=>{ return new Promise((resolved,reject)=>{ resolved({ data:"(function(){ return '12' })" }) }) }
mocktest.js
import axios from 'axios' export const fetchData=()=>{ return axios.get('/').then(res=>res.data) }
mocktest.test.js
jest.mock('./mocktest') //jest模拟mocktest内的函数 import { fetchData } from './mocktest' test('fetchData 测试', () => { return fetchData().then(data => { expect(eval(data)).toEqual('12'); }) })
4、自动模拟设置
目录结构和代码同模拟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。这就是自动模拟的运行机制。
5、异步函数模拟—同步函数不模拟
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模拟的)
- 对异步函数模拟、对同步函数不模拟,这样既可实现同步函数 和 异步函数的完美测试。
6、取消模拟
jest.unmock('./demo'); // 取消模拟
demo jest.unmock('axios'); // 取消模拟axios