Vitest如何仅在单个测试中Mock React组件?
实现单测试用Mock Child,其余用真实组件的方案
你之前的写法会把vi.mock提升到模块顶部,导致所有测试都使用Mock后的Child组件。要实现仅单个测试用Mock,其余用真实组件,可以用以下两种方案:
方案一:使用vi.doMock动态Mock(推荐)
vi.doMock不会像vi.mock那样被提升到模块顶部,能在单个测试用例中临时替换组件,且不影响其他测试。核心是在需要Mock的测试里重新导入Parent组件(刷新模块缓存)。
import { render } from '@testing-library/react'; // 先导入真实的Parent组件,供常规测试使用 import Parent from './Parent'; describe('Parent Component', () => { // 常规测试:使用真实Child组件 test('渲染真实Child组件', () => { const { getByTestId } = render(<Parent />); expect(getByTestId('real-child')).toBeInTheDocument(); }); // 仅这个测试使用Mock的Child组件 test('临时使用Mock Child组件', async () => { // 动态Mock Child组件(如果是默认导出就用default: ...) vi.doMock('./path/to/child.tsx', () => ({ Child: vi.fn(() => <div data-testid="mocked-child" />) })); // 重新导入Parent,确保它使用Mock后的Child const { default: MockedParent } = await import('./Parent'); const { getByTestId } = render(<MockedParent />); // 验证Mock组件渲染 expect(getByTestId('mocked-child')).toBeInTheDocument(); // 验证Mock函数被调用 const { Child } = await import('./path/to/child.tsx'); expect(Child).toHaveBeenCalled(); }); // 后续测试依然使用真实Child组件 test('其他测试仍使用真实Child', () => { const { getByTestId } = render(<Parent />); expect(getByTestId('real-child')).toBeInTheDocument(); }); });
方案二:全局Mock后重置实现
先全局Mock Child组件,但默认绑定真实实现,再通过mockImplementation在单个测试中替换为Mock,测试后重置回真实实现。
import { render } from '@testing-library/react'; import Parent from './Parent'; import * as ChildModule from './path/to/child'; // 保存真实的Child组件 const realChildComponent = ChildModule.Child; // 全局Mock Child,但默认使用真实实现 vi.mock('./path/to/child.tsx', async (importActual) => { const actual = await importActual<typeof ChildModule>(); return { ...actual, Child: vi.fn(actual.Child) }; }); describe('Parent Component', () => { // 每个测试前重置为真实组件 beforeEach(() => { (ChildModule.Child as jest.Mock).mockImplementation(realChildComponent); }); test('使用真实Child组件', () => { render(<Parent />); expect(ChildModule.Child).toHaveBeenCalledWith(/* 真实组件的props */); }); test('临时替换为Mock Child', () => { // 替换为自定义Mock实现 (ChildModule.Child as jest.Mock).mockImplementation(() => <div data-testid="mocked-child" />); const { getByTestId } = render(<Parent />); expect(getByTestId('mocked-child')).toBeInTheDocument(); }); test('回到真实Child组件', () => { render(<Parent />); // 断言真实组件的渲染逻辑 }); });
内容的提问来源于stack exchange,提问作者sanyooh
相关产品推荐
相关产品推荐

