Jest测试同一模块内方法调用子方法失败问题排查
问题:Jest验证模块内方法调用失败
场景与问题
我使用Jest作为测试环境,想要验证nested.js模块中的getUserData方法是否调用了同模块的setUserData方法,但测试始终失败,提示子方法未被调用。
模块代码(nested.js)
export function getUserData() { console.log("CALLING API"); const user = { name: "user", }; setUserData(user); } export function setUserData(user) { console.log("Setting user data"); }
测试代码(nested.test.js)
import * as nested from "../nested"; let storeUserDataSpy = jest.spyOn(nested, "setUserData"); describe("Get user data calls child method", () => { it("should call the child method", () => { nested.getUserData(); expect(storeUserDataSpy).toHaveBeenCalledTimes(1); }); });
测试错误信息
Expected number of calls: 1 Received number of calls: 0
我尝试过jest.mock等方法但都没解决,而且不想通过监控控制台日志来测试——这些日志不会出现在生产代码里。
解决方案
问题核心:getUserData内部直接调用的是本地的setUserData函数,而Jest的spyOn是挂载在导出的方法实例上的,所以监测不到内部的直接调用。
方法一:修改模块内调用方式
让getUserData调用模块导出的setUserData,这样spy就能捕获到调用:
// nested.js export function getUserData() { console.log("CALLING API"); const user = { name: "user", }; // 改为调用导出的方法 exports.setUserData(user); // 若使用ES模块规范,也可以自引用: // import * as self from './nested'; // self.setUserData(user); } export function setUserData(user) { console.log("Setting user data"); }
方法二:手动模拟模块
在测试文件中手动模拟整个模块,确保内部调用的是被spy的方法:
// nested.test.js import * as nested from "../nested"; // 保留原始实现,同时让方法引用导出版本 jest.mock("../nested", () => { const original = jest.requireActual("../nested"); return { ...original, getUserData: jest.fn(() => { original.getUserData(); nested.setUserData({ name: "user" }); }), setUserData: jest.fn(original.setUserData), }; }); describe("Get user data calls child method", () => { it("should call the child method", () => { nested.getUserData(); expect(nested.setUserData).toHaveBeenCalledTimes(1); expect(nested.setUserData).toHaveBeenCalledWith({ name: "user" }); }); });
方法三:重构为类(可选)
如果允许调整代码结构,把方法封装到类中,内部调用实例方法,spyOn就能正常监测:
// nested.js export class UserService { getUserData() { console.log("CALLING API"); const user = { name: "user" }; this.setUserData(user); } setUserData(user) { console.log("Setting user data"); } } // nested.test.js import { UserService } from "../nested"; describe("Get user data calls child method", () => { it("should call the child method", () => { const service = new UserService(); const spy = jest.spyOn(service, "setUserData"); service.getUserData(); expect(spy).toHaveBeenCalledTimes(1); }); });
内容的提问来源于stack exchange,提问作者AD Progress
相关产品推荐
相关产品推荐

