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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 16:27:35