首页 > web前端 > js教程 > 正文

Jest 测试中动态切换手动 Mock 与真实模块实现

聖光之護
发布: 2025-10-29 12:18:21
原创
387人浏览过

jest 测试中动态切换手动 mock 与真实模块实现

本文详细阐述了在 Jest 测试框架中,当存在模块的手动 Mock 实现时,如何在特定测试用例或测试套件中选择性地使用模块的真实实现。核心解决方案是结合使用 jest.dontMock(moduleName) 和 jest.resetModules(),以确保测试环境的灵活性和准确性。

挑战与需求

在 Jest 中进行单元测试时,我们经常会为外部依赖(如网络请求库 Axios、数据库连接等)创建手动 Mock (__mocks__/moduleName.js)。这种方式能有效地隔离被测模块,使测试聚焦于其自身逻辑,避免真实依赖带来的副作用或性能开销。

然而,在某些场景下,我们可能需要验证模块与真实依赖的集成情况,或者在同一个测试文件中,某些测试用例需要 Mock,而另一些则需要真实的模块实现。直接在测试用例内部使用 jest.mock("moduleName", () => jest.requireActual("moduleName")) 往往无法达到预期效果,因为 Jest 的模块加载机制在测试执行前就已经处理了手动 Mock,后续的 jest.mock 调用可能无法覆盖已缓存的 Mock。

解决方案:jest.dontMock 与 jest.resetModules

要实现动态切换,我们需要结合使用 Jest 提供的两个关键 API:

  1. jest.dontMock(moduleName): 此函数指示 Jest 不对指定模块进行 Mock。它会取消对该模块的任何现有 Mock 定义,包括手动 Mock。
  2. jest.resetModules(): 此函数会清除 Jest 的模块注册表(即所有已导入模块的缓存)。这至关重要,因为 jest.dontMock 仅指示 Jest "下次" 不要 Mock,而要让其生效,我们需要强制 Jest 重新加载模块。

通过在测试用例或 beforeEach 钩子中先调用 jest.resetModules() 清除模块缓存,再调用 jest.dontMock('moduleName'),可以确保当模块被重新导入时,Jest 会加载其真实实现而非 Mock。

实战示例

以下通过一个使用 axios 的具体例子,演示如何在一个测试套件中同时测试 Mocked axios 和真实 axios 的行为。

1. 设置手动 Mock (__mocks__/axios.js)

首先,创建一个 axios 的手动 Mock。这个 Mock 会拦截 axios.get 调用并返回一个预设的假数据。

ViiTor实时翻译
ViiTor实时翻译

AI实时多语言翻译专家!强大的语音识别、AR翻译功能。

ViiTor实时翻译116
查看详情 ViiTor实时翻译
// __mocks__/axios.js
let mockAxios = jest.genMockFromModule('axios');

// 为 get 方法提供一个 Mock 实现
mockAxios.get = jest.fn().mockResolvedValue({ data: 'fake' });

export default mockAxios;
登录后复制

2. 被测试的模块 (main.ts)

这是一个简单的模块,它使用 axios 发起一个 GET 请求。

// main.ts
import axios from 'axios';

export function main() {
  return axios.get('https://jsonplaceholder.typicode.com/todos/1');
}
登录后复制

3. 测试文件 (main.test.ts)

在这个测试文件中,我们将编写两个测试用例:一个使用 Mocked axios,另一个使用真实的 axios。

// main.test.ts
import { main } from './main'; // 导入被测试的模块

describe('Axios 模块切换测试', () => {
  // 在每个测试用例运行前重置模块缓存
  beforeEach(() => {
    jest.resetModules();
  });

  test('应该使用 Mocked Axios', async () => {
    // 默认情况下,如果存在手动 Mock,Jest 会使用它
    const result = await main();
    expect(result.data).toEqual('fake'); // 验证是否返回 Mock 数据
    console.log('Mocked Axios 结果:', result.data);
  });

  test('应该使用真实的 Axios', async () => {
    // 在这个测试用例中,我们取消对 axios 的 Mock
    jest.dontMock('axios');

    // 由于 beforeEach 中已经 resetModules,这里重新导入 main 模块
    // 此时 main 模块内部引用的 axios 将是真实的 axios
    const { main: actualMain } = await import('./main');
    const result = await actualMain();

    // 验证是否返回真实数据(通常是来自 API 的 JSON 对象)
    expect(result).toHaveProperty('data');
    expect(result.data).toHaveProperty('userId');
    expect(result.data).toHaveProperty('id');
    console.log('真实 Axios 结果:', result.data);
  });
});
登录后复制

4. 运行测试与结果分析

运行上述测试后,你将看到类似以下的输出:

 console.log
    Mocked Axios 结果: fake

 console.log
    真实 Axios 结果: { userId: 1, id: 1, title: 'delectus aut autem', completed: false }

 PASS  ./main.test.ts
  Axios 模块切换测试
    ✓ 应该使用 Mocked Axios (XX ms)
    ✓ 应该使用真实的 Axios (YY ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        ZZ s
登录后复制

从输出可以看出,第一个测试用例成功地使用了手动 Mock 返回了 'fake' 数据,而第二个测试用例则成功地发起了真实的网络请求,并从 jsonplaceholder.typicode.com 获取了真实的数据。这证明了 jest.dontMock 和 jest.resetModules 组合的有效性。

注意事项与最佳实践

  1. jest.resetModules() 的位置: 将 jest.resetModules() 放在 beforeEach 钩子中是推荐的做法。这确保了每个测试用例都在一个干净的模块环境中启动,避免了测试之间的状态污染。
  2. jest.dontMock() 的作用域: jest.dontMock() 调用会影响当前测试文件或 describe 块中后续的模块加载。如果你在一个 describe 块的 beforeAll 或 beforeEach 中调用它,那么该块内的所有测试都将受到影响。
  3. 模块重新导入: 当你调用 jest.resetModules() 后,任何之前导入的模块都需要重新导入才能反映新的 Mock/un-Mock 状态。在示例中,我们通过 await import('./main') 重新获取了 main 模块。
  4. 性能考量: jest.resetModules() 会清除所有模块缓存,这意味着 Jest 需要重新加载所有依赖。对于大型项目,频繁地在每个测试用例中调用 jest.resetModules() 可能会略微增加测试运行时间。在实际应用中,应权衡灵活性和性能,仅在必要时使用。
  5. 替代方案: 对于一些简单的场景,如果只是想在 Mock 中调用真实实现的一部分,jest.requireActual() 可以在 Mock 文件内部使用,例如 const actualAxios = jest.requireActual('axios'); mockAxios.post = actualAxios.post;。但这与本文讨论的动态切换整个模块 Mock 的场景有所不同。

总结

在 Jest 测试中,通过巧妙地结合使用 jest.dontMock(moduleName) 和 jest.resetModules(),我们可以实现对模块 Mock 行为的精细控制。这种方法允许开发者在同一测试套件中灵活地切换使用模块的 Mock 实现或真实实现,从而满足更复杂的测试需求,确保测试的全面性和准确性。理解并掌握这一技巧,将极大地提升 Jest 测试的灵活性和效率。

以上就是Jest 测试中动态切换手动 Mock 与真实模块实现的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号