Vitest跨测试文件复用MUI组件Mock方案求助
解决Vitest中复用MUI公共Mock的问题
问题核心原因
你遇到的错误是因为Vitest的vi.mock会被自动提升到文件顶层执行,此时你导入的mockedLibrary变量还未完成初始化,导致工厂函数无法找到该变量。另外,vi.mock是模块级别的操作,必须在文件顶层调用,不能放在beforeEach这类测试钩子中。
解决方案
下面提供两种可复用Mock的实现方式,均能避免重复编写Mock代码,同时避开vi.importActual带来的性能问题:
方案1:使用Vitest自动Mock目录(推荐)
Vitest会自动识别项目根目录下__mocks__文件夹中的文件,匹配对应模块名实现自动Mock,无需在每个测试文件中重复编写Mock逻辑。
- 创建Mock文件
在项目根目录新建__mocks__/@mui/material.jsx(路径需与模块名严格对应):
import vi from 'vitest'; // 只Mock需要用到的组件,避免全量导入提升速度 export const Button = vi.fn().mockImplementation((props) => ( <button className="mockedButton" {...props} /> )); // 可按需添加其他MUI组件的Mock // export const TextField = vi.fn().mockImplementation((props) => <input className="mockedInput" {...props} />);
- 在测试文件中启用Mock
只需在测试文件顶层调用vi.mock,Vitest会自动加载__mocks__中的配置:
// 顶层调用,自动复用公共Mock vi.mock('@mui/material'); import { render, screen } from '@testing-library/react'; import App from './App'; describe("App tests", () => { beforeEach(() => { // 每次测试前重置Mock状态,避免跨测试污染 vi.clearAllMocks(); }); it('渲染Mock按钮', () => { render(<App />); expect(screen.getByText('Test')).toBeInTheDocument(); expect(screen.getByRole('button')).toHaveClass('mockedButton'); }); });
方案2:创建公共Mock工厂函数
如果不想依赖自动Mock目录,可以编写一个返回Mock对象的公共函数,确保vi.mock提升后能正确调用:
- 创建公共Mock函数文件
mockMUI.jsx:
import vi from 'vitest'; export default function getMuiMocks() { return { Button: vi.fn().mockImplementation((props) => ( <button className="mockedButton" {...props} /> )), // 按需添加其他组件Mock }; }
- 在测试文件中使用:
import getMuiMocks from './mockMUI'; // 顶层调用Mock,传入公共工厂函数 vi.mock('@mui/material', () => getMuiMocks()); import { render, screen } from '@testing-library/react'; import App from './App'; describe("App tests", () => { beforeEach(() => { vi.clearAllMocks(); }); it('渲染Mock按钮', () => { render(<App />); // 测试逻辑 }); });
关键注意事项
- 永远不要在
beforeEach、it等测试钩子中调用vi.mock,必须放在文件顶层作用域 - 避免直接导出Mock对象供
vi.mock使用,改用函数返回的方式,确保变量初始化顺序正确 - 若只需Mock部分组件,不要使用
vi.importActual全量导入原模块,只导出需要Mock的组件即可提升测试速度
内容的提问来源于stack exchange,提问作者Basile Parent
相关产品推荐
相关产品推荐

