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

如何为独立工具函数及内部函数设置Jest spyOn?

如何为默认导出工具函数中的内部函数设置Jest Spy?

我明白你的困扰——平时用jest.spyOn监听类或对象的方法得心应手,但碰到默认导出的工具函数里的内部私有函数时,就不知道怎么下手了。你遇到的核心问题是:Funct2是模块内部的私有函数,没有被导出,测试代码根本访问不到它,更别说给它加监听了。下面给你几个可行的解决方案,按需选择:

方案1:临时导出内部函数(快速解决,不改动核心逻辑)

如果不想大改代码结构,可以给Funct2加一个命名导出,专门供测试使用(生产环境不会影响,因为没人会导入这个内部函数)。

修改原代码:

const Funct1 = props => { 
  if(props){ 
    Funct2(props); // 假设这里传的是props,根据你的实际代码调整参数
  } 
  // 其他逻辑
};
const Funct2 = props => { 
  // 你的业务逻辑
  return true 
};

export default Funct1;
export { Funct2 }; // 新增命名导出,仅用于测试

测试代码:

import Funct1 from "../../../src/components/Funct1";
import * as module from "../../../src/components/Funct1"; // 导入整个模块

describe("Test the Thing", () => {
  it("New Test", () => {
    const props = { active: true, agentStatus: "online" };
    
    // 监听模块导出的Funct2,并设置mock返回值
    const funct2Spy = jest.spyOn(module, "Funct2").mockReturnValue(true);
    
    Funct1(props);
    
    // 验证Funct2被正确调用,以及返回值符合预期
    expect(funct2Spy).toHaveBeenCalledWith(props);
    expect(funct2Spy).toHaveReturnedWith(true);
    
    // 测试结束后恢复原函数,避免影响其他测试
    funct2Spy.mockRestore();
  });
});

方案2:重构代码,拆分依赖(更优雅的长期方案)

如果项目允许重构,把Funct2提取到单独的工具模块是更干净的做法——这样不仅测试方便,代码的复用性和可维护性也更好。

步骤1:拆分Funct2到单独模块

新建src/utils/funct2.js:

export default props => {
  // 原Funct2的业务逻辑
  return true;
};

步骤2:修改原模块引入Funct2

import Funct2 from "../utils/funct2";

const Funct1 = props => { 
  if(props){ 
    Funct2(props); 
  } 
  // 其他逻辑
};

export default Funct1;

步骤3:测试代码模拟Funct2模块

import Funct1 from "../../../src/components/Funct1";
import Funct2 from "../../../src/utils/funct2";

// 自动模拟Funct2模块
jest.mock("../../../src/utils/funct2");

describe("Test the Thing", () => {
  it("New Test", () => {
    const props = { active: true, agentStatus: "online" };
    
    // 设置Funct2的mock返回值
    Funct2.mockReturnValue(true);
    
    Funct1(props);
    
    // 验证调用情况
    expect(Funct2).toHaveBeenCalledWith(props);
    expect(Funct2).toHaveReturnedWith(true);
  });
});

方案3:不修改原代码,用模块重写模拟(适合无法改动原代码的场景)

如果完全不能修改原代码,可以用Jest的模块重写功能,手动实现Funct1并替换内部的Funct2:

import Funct1 from "../../../src/components/Funct1";

// 重写整个模块
jest.mock("../../../src/components/Funct1", () => {
  // 保留原模块的其他导出(这里只有默认导出Funct1)
  const original = jest.requireActual("../../../src/components/Funct1");
  // 创建Funct2的mock函数
  const mockFunct2 = jest.fn().mockReturnValue(true);
  
  return {
    ...original,
    __esModule: true,
    default: (props) => {
      // 手动复刻原Funct1的逻辑,但替换Funct2为mock版本
      if (props) {
        mockFunct2(props);
      }
      // 如果原Funct1有返回值,记得同步返回
      // return original.default(props); 
      // 注意:如果原Funct1逻辑复杂,这种方式容易和原代码脱节,慎用
    },
    // 暴露mock函数供测试验证
    mockFunct2
  };
});

// 导入我们暴露的mock函数
import { mockFunct2 } from "../../../src/components/Funct1";

describe("Test the Thing", () => {
  it("New Test", () => {
    const props = { active: true, agentStatus: "online" };
    
    Funct1(props);
    
    expect(mockFunct2).toHaveBeenCalledWith(props);
    expect(mockFunct2).toHaveReturnedWith(true);
  });
});

注意事项:

  • 方案3适合临时应急,因为手动复刻原函数逻辑容易随着原代码更新而失效,长期来看还是方案2更靠谱。
  • 不管用哪种方案,测试后记得用mockRestore()或者jest.clearAllMocks()清理mock,避免影响其他测试用例。

内容的提问来源于stack exchange,提问作者Phil Lucks

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:03:29