跳至主内容
版本:29.7

绕过模块模拟

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

Jest 允许您在测试中模拟整个模块,这在验证代码是否正确调用模块函数时非常有用。但有时您可能希望在_测试文件_中使用被模拟模块的某些部分,这时就需要访问原始实现而非模拟版本。

假设要为这个 createUser 函数编写测试用例:

createUser.js
import fetch from 'node-fetch';

export const createUser = async () => {
const response = await fetch('https://website.com/users', {method: 'POST'});
const userId = await response.text();
return userId;
};

测试需要模拟 fetch 函数以确保其被调用且不实际发起网络请求。但您还需用 Response 对象(包裹在 Promise 中)来模拟 fetch 的返回值,因为我们的函数依赖它获取已创建用户的 ID。您最初可能会尝试这样编写测试:

jest.mock('node-fetch');

import fetch, {Response} from 'node-fetch';
import {createUser} from './createUser';

test('createUser calls fetch with the right args and returns the user id', async () => {
fetch.mockReturnValue(Promise.resolve(new Response('4')));

const userId = await createUser();

expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith('https://website.com/users', {
method: 'POST',
});
expect(userId).toBe('4');
});

然而运行该测试会发现 createUser 函数会抛出错误:TypeError: response.text is not a function。这是因为从 node-fetch 导入的 Response 类已被模拟(由测试文件顶部的 jest.mock 调用导致),导致其行为异常。

为解决此类问题,Jest 提供了 jest.requireActual 辅助方法。要使上述测试生效,请在测试文件中按如下方式修改导入语句:

// BEFORE
jest.mock('node-fetch');
import fetch, {Response} from 'node-fetch';
// AFTER
jest.mock('node-fetch');
import fetch from 'node-fetch';
const {Response} = jest.requireActual('node-fetch');

这使得测试文件能从 node-fetch 导入真实的 Response 对象而非模拟版本,从而确保测试正确通过。