如何用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(); }); });
为啥原测试失败?
- 你试图直接spyOn
a.function2.function3.dbCall,这根本行不通:dbCall没被导出,而且模块之间的引用不是链式可访问的,你没法从a模块直接拿到深层的dbCall。 - 异步测试没处理好:原代码里直接用
function1.then(),但没告诉Jest要等异步操作完成,Jest会直接结束测试,断言根本不会执行。 - 原代码本身语法错误太多,连运行都做不到,测试自然失败。
内容的提问来源于stack exchange,提问作者Cyril Arathy
相关产品推荐
相关产品推荐

