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

如何用Jest深度模拟三层嵌套未导出函数以避免数据库调用?

解决Jest模拟三层嵌套未导出函数的问题

我需要模拟一个三层嵌套的未导出函数,避免向数据库发送真实请求。结构是:c.js的function3里有个没导出的dbCall,b.js的function2调用c.function3,a.js的function1调用b.function2。但我在a.test.js里用Jest模拟dbCall一直失败,求帮忙。

原文件代码

c.js

exports.c.function3 = {
dbCall.then((data)=>data);
}

b.js

require("./c");
exports.b.function2 = ()=>{
c.function3()
.then((data)=>data);
}

a.js

require("./b");
exports.function1 = ()=>{
b.function2()
.then((data)=>data);
}

a.test.js

require("./a");
describe("Test cases a",()=>{


test("function1 should return data from db",()=>{
const dbCall = jest.spyOn(a,'function2.function3.dbCall');
dbCall.mockImplementation(()=>[1,2,3]);
function1.then((data)=>{
expect(data.length).toBe(3);
});
}
})

解决方案

先得把原代码里的语法错误改了,这些错误会导致代码根本跑不起来,更别说测试了:

1. 修正模块导出与函数定义

原代码的导出方式、函数写法全有问题,先把各文件改成正常可运行的样子:

修正后的c.js

// 未导出的dbCall,模拟真实数据库请求
const dbCall = () => {
  return Promise.resolve("真实数据库返回的数据");
};

// 正确导出function3
exports.function3 = () => {
  return dbCall().then((data) => data);
};

修正后的b.js

const c = require("./c");

// 正确导出function2
exports.function2 = () => {
  return c.function3().then((data) => data);
};

修正后的a.js

const b = require("./b");

// 正确导出function1
exports.function1 = () => {
  return b.function2().then((data) => data);
};

2. 写正确的Jest测试代码

因为dbCall是c.js里没导出的私有函数,你没法直接用spyOn抓它,得通过模拟导出的上层函数(比如function3)来拦截数据库请求,或者直接mock整个c模块:

方案一:模拟c模块的function3

const a = require("./a");
const c = require("./c");

describe("Test cases a", () => {
  test("function1应该返回预设的模拟数据", async () => {
    // 把c.function3替换成返回预设Promise的mock函数
    jest.spyOn(c, "function3").mockResolvedValue([1, 2, 3]);

    // 异步函数必须用await等结果,不然Jest会提前结束测试
    const data = await a.function1();
    expect(data.length).toBe(3);

    // 测试完恢复原函数,别影响其他测试
    c.function3.mockRestore();
  });
});

方案二:用jest.mock直接重写整个c模块

const a = require("./a");

// 直接mock整个c模块,指定function3的返回值
jest.mock("./c", () => ({
  function3: jest.fn().mockResolvedValue([1, 2, 3])
}));

describe("Test cases a", () => {
  test("function1应该返回预设的模拟数据", async () => {
    const data = await a.function1();
    expect(data.length).toBe(3);
    // 还能验证function3有没有被调用
    const c = require("./c");
    expect(c.function3).toHaveBeenCalled();
  });
});

为啥原测试失败?

  • 你试图直接spyOna.function2.function3.dbCall,这根本行不通:dbCall没被导出,而且模块之间的引用不是链式可访问的,你没法从a模块直接拿到深层的dbCall。
  • 异步测试没处理好:原代码里直接用function1.then(),但没告诉Jest要等异步操作完成,Jest会直接结束测试,断言根本不会执行。
  • 原代码本身语法错误太多,连运行都做不到,测试自然失败。

内容的提问来源于stack exchange,提问作者Cyril Arathy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 11:23:23