Jest 是 Facebook 开发的 JavaScript 测试框架,被广泛应用于前端项目中的单元测试和集成测试等场景。在 Jest 的测试代码中,mock 功能既是必不可少的,也是使用 Jest 时容易出现问题的一个关键点。本文将结合代码示例,从多个方面介绍了在 Jest 测试中遇到的 mock 问题及解决方式,希望能够对前端开发者在 Jest 测试中提供一些有用的指导。
问题 1:如何正确 Mock 接口请求?
在使用 Jest 测试前端项目的过程中,最常见的 mock 场景就是模拟接口请求过程。在 Jest 中,可以使用 jest.mock() 方法来模拟接口请求。但是,要想在测试代码中正确地使用 jest.mock(),需要注意以下几个问题:
Mock 的文件路径要正确。对于需要 Mock 的文件,应该使用相对路径,而不是绝对路径,以便在不同机器上的环境中能够正常运行。
需要 Mock 的文件必须要导出相应的对象或方法。在执行 Mock 后,Jest 会自动根据需要 Mock 的对象或方法的返回值来模拟接口请求的响应结果。如果需要 Mock 的文件中没有导出相应的对象或方法,那么就不会有任何模拟响应结果产生。
Mock 后需要等待 Promise 的执行结果再进行下一步操作。由于接口请求通常都是异步操作,所以在使用
jest.mock()方法进行接口请求的模拟时,需要在调用模拟函数后等待 Promise 的执行结果再进行下一步操作。通常可以使用 Jest 提供的async/await语法糖来解决这个问题。
下面是一个示例代码,演示了如何使用 jest.mock() 方法来模拟接口请求过程。
// www.javascriptcn.com code example
// api.js
export function fetchData(url) {
return fetch(url).then((response) => {
return response.json();
});
}
// index.js
import { fetchData } from './api';
export function fetchDataAsync(url) {
return fetchData(url)
.then((data) => {
return data;
})
.catch((error) => {
console.error(error);
});
}
// index.test.js
import { fetchDataAsync } from './index';
jest.mock('./api');
test('fetchDataAsync should return data', async () => {
const data = { name: 'Tom', age: 18 };
const mockedFetchData = jest.fn().mockResolvedValue(data);
require('./api').fetchData.mockImplementation(mockedFetchData);
const res = await fetchDataAsync('https://localhost:8888');
expect(res).toEqual(data);
});在上面的示例代码中,我们将 api.js 文件中的 fetchData 方法进行了 Mock。在测试代码中,我们利用 jest.fn() 方法创建了一个模拟函数,并将其作为 Mock 的返回值。然后,我们调用 api.js 中的 fetchData 方法,得到模拟的数据结果,并通过使用 Jest 提供的 async/await 语法糖,等待 Promise 的执行结果后,再进行断言测试。
问题 2:如何 Mock 全局变量?
在前端项目中,很多时候我们会使用全局变量来存储全局的配置信息或者全局的状态。在编写 Jest 测试代码时,我们可能需要 Mock 全局变量,以便更好地测试业务逻辑。那么,如何在 Jest 中正确地 Mock 全局变量呢?
在 Jest 中,Mock 全局变量的方法非常简单,只需要使用 global 对象即可。下面是一个示例代码,演示了如何使用 global 对象来 Mock 全局变量。
// www.javascriptcn.com code example
// index.js
export const GlobalVar = {
name: 'Tom',
age: 18,
};
// index.test.js
import { GlobalVar } from './index';
test('should mock globalvar', () => {
const mockGlobalVar = {
...GlobalVar,
name: 'Jerry',
age: 20,
};
global.GlobalVar = mockGlobalVar;
expect(GlobalVar).toEqual(mockGlobalVar);
});在上面的示例代码中,我们对 GlobalVar 进行了 Mock,并使用 global.GlobalVar 对其进行了覆盖。然后,我们在测试代码中通过断言验证全局变量是否被正确地 Mock。
问题 3:如何区分 Mock 的函数和原函数?
在 Jest 中,使用 Mock 功能时需要非常注意,避免将 Mock 的函数和被 Mock 的函数混淆。否则,测试结果将可能出现非常奇怪的问题。那么,如何才能正确地区分 Mock 的函数和原函数呢?
通常,为了避免混淆,我们可以在 Mock 函数的名称前或后添加 mock、mocked、mockFn 等后缀,以便更加方便地区分。同时,在使用 Mock 函数时,也需要谨慎使用 Jest 提供的一些 Mock 方法,如 mock.calls、mock.instances 等,否则也可能会造成 Mock 函数和原函数的混淆。
下面是一个示例代码,演示了如何在 Mock 函数和原函数之间正确地区分。
// www.javascriptcn.com code example
// index.js
export function add(a, b) {
return a + b;
}
// index.test.js
import { add } from './index';
test('should be able to mock func', () => {
const mockAdd = jest.fn(add);
mockAdd.mockImplementation((a, b) => a - b);
const res1 = add(3, 6);
const res2 = mockAdd(3, 6);
expect(res1).toEqual(9);
expect(res2).toEqual(-3);
expect(add).not.toHaveBeenCalled();
expect(mockAdd).toHaveBeenCalled();
});在上面的示例代码中,我们通过 jest.fn() 函数来创建了一个 Mock 函数 mockAdd。然后,我们打印 mockAdd 和 add 的调用信息,可以看到它们被正确地区分。最后,我们验证了使用 add 调用和使用 mockAdd 调用的结果是不同的。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d016d8e46428fe9ecaa9d4