You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jest.js无法模拟嵌套本地函数的技术问询

解决Jest手动模拟本地嵌套函数不生效的问题

这个问题我之前也踩过坑,核心原因是模块导入顺序错误——Jest会优先处理所有顶层的import语句,你在模拟模块之后才导入依赖它的getNewJob,导致getNewJob已经绑定了原始的getNextId函数,后续的模拟根本覆盖不到。

正确解决方案:用jest.mock提前模拟模块

jest.mock会被Jest自动提升到所有代码执行之前,确保目标模块被导入时拿到的是模拟版本,而不是原始模块。

基础版测试代码

// 第一步:先模拟db模块,必须放在所有import之前
jest.mock('../../db', () => ({
  getNextId: jest.fn(() => Promise.resolve(0)) // 直接指定模拟返回值
}));

// 第二步:导入依赖模块,此时它们会使用模拟后的getNextId
import { getNewJob, Job } from '../../app/job';
import { someUtilMethod } from '../../app/util';

describe('Job creation tests', () => {
  it('should generate a Job with mocked id', async () => {
    // 调用目标函数(现在会用模拟的getNextId)
    const job = await getNewJob();
    const testVal = someUtilMethod(job);

    // 执行断言
    expect(job.id).toBe(0);
    // 这里添加你对someUtilMethod结果的断言,比如:
    // expect(testVal).toBe('expected-value');
  });
});

动态修改模拟返回值(多测试用例场景)

如果需要在不同测试用例中返回不同的id,可以通过jest.Mock类型断言来修改模拟函数的返回值:

// 仍然先提前模拟模块
jest.mock('../../db', () => ({
  getNextId: jest.fn() // 先初始化一个空的mock函数
}));

import { getNextId } from '../../db';
import { getNewJob } from '../../app/job';

describe('Job creation tests', () => {
  it('should use id 0 in first case', async () => {
    // 设置当前用例的返回值
    (getNextId as jest.Mock).mockResolvedValue(0);
    const job = await getNewJob();
    expect(job.id).toBe(0);
  });

  it('should use id 100 in second case', async () => {
    // 覆盖为新的返回值
    (getNextId as jest.Mock).mockResolvedValue(100);
    const job = await getNewJob();
    expect(job.id).toBe(100);
  });
});

为什么你原来的方法无效?

你用jest.createMockFromModule创建的模拟模块只是一个普通对象,并没有替换Jest内部的模块缓存。当你后续导入../../app/job时,它会从缓存中加载原始的../../db模块,绑定真实的getNextId函数,所以你的模拟代码根本没被调用到。

只有jest.mock能真正覆盖Jest的模块缓存,确保所有依赖该模块的代码都使用模拟版本。

内容的提问来源于stack exchange,提问作者Matt Weaver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:10:46