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

如何用Jest与React Native Testing Library模拟外部函数测试组件?

问题描述

我有一个调用外部函数的React Native组件,代码如下:

// AComponent.js
import { Text, View } from "react-native";
import { getAString } from "./utils/function";

const AComponent = () => {
  return (
    <View>
      <Text>{getAString()}</Text>
    </View>
  );
};

export default AComponent;

外部函数getAString定义在单独文件中:

// function.js
export function getAString(): string {
  return "This comes from GetAString";
}

尝试测试AComponent时模拟这个函数,写了如下测试代码:

var AComponent = require("../src/AComponent").default;
import { getAString } from "../src/utils/function";
import { render, screen, fireEvent } from "@testing-library/react-native";

describe("A Component's test", () => {
  it("mocking the function", async () => {
    render(<AComponent />);

    jest.spyOn(AComponent, "getAString").mockImplementation(() => {
      return "This is a mocked result";
    });

    const element = screen.getByText("This is a mocked result");
    expect(element).toBeTruthy();
  });
});

但测试运行失败,报错:

Cannot spy on the getAString property because it is not a function; undefined given instead

推测是测试代码错误地认为getAString是AComponent的属性,但实际并非如此,请问正确的模拟方法是什么?

正确的模拟方法

要解决这个问题,得直接模拟getAString所在的模块,而非尝试在组件实例上查找该函数,以下是两种常用的正确实现方式:

方法一:使用jest.spyOn模拟模块导出的函数

import AComponent from "../src/AComponent";
import * as functionModule from "../src/utils/function";
import { render, screen } from "@testing-library/react-native";

describe("A Component's test", () => {
  it("mocks the external function correctly", () => {
    // 先模拟函数,再渲染组件
    const mockGetAString = jest.spyOn(functionModule, "getAString")
      .mockReturnValue("This is a mocked result");

    render(<AComponent />);

    expect(screen.getByText("This is a mocked result")).toBeTruthy();
    // 验证函数被调用
    expect(mockGetAString).toHaveBeenCalled();
    
    // 测试结束后恢复原函数,避免影响其他测试
    mockGetAString.mockRestore();
  });
});

核心要点:

  • 将整个function模块导入为functionModule,这样就能用jest.spyOn监听模块导出的getAString函数
  • 必须先完成函数模拟,再渲染组件,否则组件会优先执行原函数逻辑
  • 用mockRestore()在测试完成后恢复原函数,保证不同测试用例之间的隔离性

方法二:使用jest.mock直接Mock整个模块

如果需要在多个测试用例中重复使用同一模拟逻辑,可以直接Mock整个模块:

import AComponent from "../src/AComponent";
import { getAString } from "../src/utils/function";
import { render, screen } from "@testing-library/react-native";

// 全局Mock整个function模块,该代码会自动提升到文件顶部执行
jest.mock("../src/utils/function", () => ({
  getAString: jest.fn(() => "This is a mocked result")
}));

describe("A Component's test", () => {
  it("uses the mocked function", () => {
    render(<AComponent />);
    
    expect(screen.getByText("This is a mocked result")).toBeTruthy();
    expect(getAString).toHaveBeenCalled();
  });

  it("can override the mock for a single test", () => {
    // 临时修改Mock的返回值
    getAString.mockReturnValue("Another mocked value");
    render(<AComponent />);
    
    expect(screen.getByText("Another mocked value")).toBeTruthy();
  });
});

核心要点:

  • jest.mock会被Jest自动提升到文件顶部执行,确保组件渲染时已经使用了Mock后的函数
  • 可以在单个测试用例中,通过mockReturnValue或mockImplementation临时修改Mock的返回值
  • 所有测试结束后Jest会自动清理这些Mock,无需手动恢复

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 03:20:52