You need to enable JavaScript to run this app. Jest+Enzyme测试React组件Mock API报错,提示fetchTheComments为空
优惠活动
大模型
产品
解决方案
定价
更多

Jest+Enzyme测试React组件Mock API报错,提示fetchTheComments为空

报错根源与排查修正

核心报错原因

  • 函数组件实例访问逻辑错误:App是无状态函数组件,Enzyme挂载这类组件时wrapper.instance()会返回null,不存在class组件的this实例指向;且组件内部定义的fetchTheComments是函数闭包内的局部变量,不会对外暴露。测试代码中通过wrapper.instance().fetchTheComments()访问的方式,最终会拿到null值,这就是控制台提示“fetchTheComments函数为空”的直接原因。
  • 业务代码存在React渲染反模式:<p>标签内直接在渲染阶段调用异步函数fetchTheComments(),每次组件重渲染都会重复触发API请求,且异步函数返回的是Promise对象,JSON.stringify(Promise)只能得到空对象{},根本无法拿到实际接口返回内容,还会触发不受控的重复网络请求,干扰测试执行。
  • Mock逻辑完全未生效:测试代码中自定义的mockAxiosApi没有和真实的axios模块做绑定,缺少jest.mock("axios")声明,Jest根本不会将组件内导入的真实axios替换为自定义mock对象,等于mock逻辑和实际运行的代码完全脱节,自然无法拦截API请求。
  • 测试用例逻辑顺序错误:当前测试流程是先模拟按钮点击触发请求,再给axios绑定mock实现,触发请求时mock还未挂载,无法拦截请求;且用例中查找的comments节点在组件中根本不存在,没有对应的DOM元素可以匹配;所有异步操作完成前就直接做断言,拿到的都是初始渲染的空状态。

修正方案

业务代码修正

首先要消除渲染阶段的异步调用反模式,用状态管理存接口返回值,代码示例:

import React, { useState } from "react";
import "./App.css";
import axios from "axios";

function App() {
  // 新增状态存储接口返回的评论数据
  const [comments, setComments] = useState(null);

  const fetchTheComments = async () => {
    try {
      const commentsFetched = await axios.get(
        `https://jsonplaceholder.typicode.com/comments/1`
      );
      // 请求成功后更新状态,触发组件重渲染
      setComments(commentsFetched.data);
    } catch (e) {
      console.error("请求出错", e);
    }
  };

  return (
    <div className="App">
      <h1>Testing Jest-Enzyme</h1>
      <button
        id="fetch-comments"
        onClick={fetchTheComments}
      >
        Fetch
      </button>
      {/* 给p标签加专属id方便测试断言 */}
      <p id="comments-content">
        {comments ? JSON.stringify(comments) : ""}
      </p>
    </div>
  );
}

export default App;

测试代码修正

  • 补充Jest的axios模块mock声明,替换真实网络请求
  • 去掉对组件内部私有函数的直接访问,通过模拟用户交互触发业务逻辑
  • 调整mock绑定的顺序,在模拟点击前完成mock实现的配置
  • 等待异步操作执行完成后再做DOM断言
    修正后的测试示例:
import App from "./App";
import { mount } from "enzyme";
// 导入真实axios,通过Jest声明将其替换为自动生成的mock
import axios from "axios";
jest.mock("axios");

// 工具方法:等待所有异步微任务执行完成
const waitForAsync = () => new Promise(resolve => setTimeout(resolve, 0));

describe("App组件测试", () => {
  let wrapper;
  beforeEach(() => {
    // 每个用例前重置mock状态,避免用例间的逻辑污染
    jest.clearAllMocks();
    wrapper = mount(<App />);
  });

  test("渲染正确的标题", () => {
    expect(wrapper.find("h1").text()).toBe("Testing Jest-Enzyme");
  });

  test("点击按钮成功请求并渲染评论内容", async () => {
    // 先绑定mock实现,再触发用户点击
    axios.get.mockResolvedValue({
      data: { id: 1, body: "测试评论内容" }
    });
    // 模拟用户点击按钮的交互
    wrapper.find("#fetch-comments").simulate("click");
    // 等待异步请求、状态更新、组件重渲染全流程完成
    await waitForAsync();
    wrapper.update();
    // 断言p标签的实际渲染内容
    expect(wrapper.find("#comments-content").text()).toBe(
      JSON.stringify({ id: 1, body: "测试评论内容" })
    );
    // 断言接口请求参数符合预期
    expect(axios.get).toHaveBeenCalledWith(
      "https://jsonplaceholder.typicode.com/comments/1"
    );
  });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.31 07:57:04