使用 React Testing Library 进行集成测试
在测试中渲染组件、触发事件,并断言可见输出而不是内部实现。
使用 React Testing Library 进行集成测试 是 CoddyKit 上的免费 React Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 React Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 React Academy 课程共包含 4 节课。
什么是 React Testing Library
React Testing Library 鼓励从用户视角进行测试:渲染组件,以用户的方式与组件交互,并断言可见输出,而不是实现细节。
设置
Create React App 和 Vite 的 React 模板都已包含 RTL。手动设置时,请安装 @testing-library/react 和 @testing-library/jest-dom。
// package.json
// "@testing-library/react": "^14.0.0",
// "@testing-library/jest-dom": "^6.0.0"
// setupTests.ts
import '@testing-library/jest-dom';渲染组件
render() 会在虚拟 DOM 中挂载组件,并返回针对渲染结果设置作用域的查询函数。
import { render, screen } from '@testing-library/react';
import { Button } from './Button';
test('renders button label', () => {
render(<Button label="Submit" onClick={() => {}} />);
expect(screen.getByText('Submit')).toBeInTheDocument();
});查询元素
请按以下顺序优先选择查询方式:getByRole > getByLabelText > getByPlaceholderText > getByText。基于角色的查询会匹配可访问性语义。
// Best: query by role
const button = screen.getByRole('button', { name: /submit/i });
// Good: query by label (for form inputs)
const input = screen.getByLabelText('Email address');
// Acceptable: query by text
const heading = screen.getByText('Welcome');触发事件
请使用来自 @testing-library/user-event 的 userEvent(首选),或使用 fireEvent(基础方式)。userEvent 会模拟真实的浏览器交互,包括获得焦点和失去焦点。
import userEvent from '@testing-library/user-event';
test('types into input', async () => {
const user = userEvent.setup();
render(<SearchBar />);
const input = screen.getByRole('textbox');
await user.type(input, 'react');
expect(input).toHaveValue('react');
});测试表单提交
渲染表单,使用 userEvent.type 填写输入项,点击提交,然后断言结果(成功消息、页面跳转或回调调用)。
test('submits the login form', async () => {
const onLogin = jest.fn();
const user = userEvent.setup();
render(<LoginForm onLogin={onLogin} />);
await user.type(screen.getByLabelText('Email'), 'test@example.com');
await user.type(screen.getByLabelText('Password'), 'password123');
await user.click(screen.getByRole('button', { name: /log in/i }));
expect(onLogin).toHaveBeenCalledWith({ email: 'test@example.com', password: 'password123' });
});断言可见性
jest-dom 提供的 toBeInTheDocument()、toBeVisible() 和 toHaveValue() 等匹配器可以让断言更易读。
expect(screen.getByText('Error: required')).toBeInTheDocument();
expect(screen.getByRole('dialog')).toBeVisible();
expect(screen.getByRole('textbox')).toHaveValue('hello');
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();测试条件渲染
请使用 queryBy(元素不存在时返回 null)断言元素未被渲染;当您预期元素存在时,请使用 getBy。
test('shows error message when validation fails', async () => {
const user = userEvent.setup();
render(<SignUpForm />);
await user.click(screen.getByRole('button', { name: /submit/i }));
expect(screen.getByText('Email is required')).toBeInTheDocument();
});使用提供者包装组件
大多数组件都需要上下文或路由器。请在 render 调用中使用提供者包装组件,或者创建自定义的 renderWithProviders 辅助函数。
function renderWithProviders(ui: React.ReactElement) {
return render(
<QueryClientProvider client={new QueryClient()}>
<MemoryRouter>
{ui}
</MemoryRouter>
</QueryClientProvider>
);
}
test('shows user data', () => {
renderWithProviders(<UserProfile />);
});测试状态变化
先对组件执行操作,然后断言新的状态已反映在界面中。使用 userEvent 时,RTL 会自动将大多数交互包装在 act 中。
test('counter increments', async () => {
const user = userEvent.setup();
render(<Counter />);
expect(screen.getByText('Count: 0')).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: /increment/i }));
expect(screen.getByText('Count: 1')).toBeInTheDocument();
});Screen 调试辅助工具
调用 screen.debug() 将当前渲染的 HTML 输出到控制台;当查询失败并且您需要查看实际渲染内容时,这非常有用。
test('debugging a failing query', () => {
render(<MyComponent />);
screen.debug(); // prints rendered HTML
screen.getByRole('button', { name: /save/i }); // then inspect output
});快速检查
在 React Testing Library 中测试按钮时,应优先使用哪种查询?
回顾
RTL 会渲染组件,并通过基于角色的查询和 userEvent 与组件交互。请使用所需的提供者包装组件,使用 jest-dom 匹配器编写易读的断言,并在断言元素不存在时优先使用 queryBy。
常见问题解答
「使用 React Testing Library 进行集成测试」课时是免费的吗?
是的 — 「使用 React Testing Library 进行集成测试」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 React Academy 课程的其余内容,请升级到 CoddyKit PRO。 React Academy 课程共包含 4 节课。
「使用 React Testing Library 进行集成测试」这节课中我会学到什么?
在测试中渲染组件、触发事件,并断言可见输出而不是内部实现。 你通过在浏览器中直接运行的动手代码来练习 React Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 React Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 React Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「使用 React Testing Library 进行集成测试」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 React Academy 课中编写并运行代码吗?
能。每节 React Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 使用 React Testing Library 进行集成测试
- 使用 MSW 测试异步界面与 API 调用
- Playwright for React 入门
- 端到端测试表单与用户流程