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

如何使用Jest和React Testing Library Mock React子组件

Jest 同模块子组件Mock方案

报错根因

你当前写法报错的核心原因有两个:

  1. Tree 和 Child 定义在同一个模块文件中,Tree 内部默认调用的是模块内部作用域的Child函数,你通过jest.doMock修改的只是模块的导出值,并不会影响模块内部的变量引用,所以Tree渲染时无法读取到mock后的Child。
  2. 测试顶部提前导入了Tree组件,模块已经被加载进Jest缓存,后续的doMock动态修改不会覆盖已缓存的模块内容。

推荐解决方案:拆分组件到独立模块

这是最符合项目开发规范的方案,拆分后单独mock子组件所属模块即可:

第一步:拆分组件文件

// ./features/test-samples/Child.js
export const Child = () => {
  return <h1>Child</h1>
}
// ./features/test-samples/tree.js
import { Child } from './Child'
export const Tree = () => {
  return (<>
    <h1>Tree</h1>
    <Child/>
  </>)
}

第二步:编写测试用例

import { render as rtlRender } from '@testing-library/react';

// 每次测试前清除模块缓存,避免用例间互相影响
beforeEach(() => {
  jest.resetModules()
})

describe.only('Test <Tree/> component', () => {
  test("test mock child", () => {
    // mock子组件模块,必须放在require父组件之前执行
    jest.mock('./features/test-samples/Child', () => ({
      Child: jest.fn(() => <div>Mocked Child</div>)
    }))
    // 动态导入父组件
    const { Tree } = require('./features/test-samples/tree')
    const { getByText } = rtlRender(<Tree />)
    
    expect(getByText(/Tree/i)).toBeInTheDocument()
    expect(getByText(/Mocked Child/i)).toBeInTheDocument()
  });
})

兼容方案:不拆分模块的修改方式

如果你一定要保留两个组件在同一个文件中,可以修改Tree的引用逻辑,让它读取模块导出的Child而不是内部变量:

修改原组件

// ./features/test-samples/tree.js
export const Child = () => {
    return (
        <h1>Child</h1>
    )
}

export const Tree = () => {
    return (<>
        <h1>Tree</h1>
        {/* 引用模块导出的Child,mock修改导出值后会生效 */}
        <module.exports.Child/>
    </>)
}

测试用例即可正常运行

你原来的测试写法加上清除缓存的逻辑就可以正常执行:

beforeEach(() => {
  jest.resetModules()
})

test("test mock child", () => {
  const actualModule = jest.requireActual('./features/test-samples/tree');
  jest.doMock('./features/test-samples/tree', () => {
    return {
      ...actualModule,
      Child: jest.fn(() => <div>Mocked Child</div>),
    }
  });
  const { Tree } = require('./features/test-samples/tree'); 
  const { getByText } = rtlRender(<Tree />);
  expect(getByText(/Mocked Child/i)).toBeInTheDocument();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 15:57:03