0Pricing
React Academy · 课时

使用 MSW 测试异步界面与 API 调用

使用 Mock Service Worker 模拟 HTTP 请求,测试获取数据的组件。

使用 MSW 测试异步界面与 API 调用 是 CoddyKit 上的免费 React Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 React Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 React Academy 课程共包含 4 节课。

为什么使用 Mock Service Worker

MSW 会在网络层拦截 HTTP 请求:在浏览器中使用 Service Worker,在 Node 中使用 http 拦截器。这样无需修改应用代码即可模拟接口。

安装 MSW

请安装 MSW,并为 Jest/Vitest 测试设置 Node 拦截器。

// npm install msw --save-dev

// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw';

export const handlers = [
  http.get('/api/users', () => {
    return HttpResponse.json([{ id: 1, name: 'Alice' }]);
  }),
];

设置模拟服务器

使用您的 handlers 创建 setupServer 实例,并在测试前调用 server.listen(),在每次测试后调用 server.resetHandlers(),在所有测试结束后调用 server.close()。

import { setupServer } from 'msw/node';
import { handlers } from './handlers';

const server = setupServer(...handlers);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

测试会发起数据请求的组件

渲染会触发数据请求的组件。MSW 会拦截请求并返回模拟数据。请断言数据加载完成后用户看到的内容。

test('shows user list after fetch', async () => {
  render(<UserList />);
  expect(screen.getByText('Loading...')).toBeInTheDocument();
  expect(await screen.findByText('Alice')).toBeInTheDocument();
});

用于异步界面的 findBy 查询

findBy 查询会返回一个承诺,在元素出现时解析(默认超时时间最长为 1 秒)。请将其用于异步操作后才出现的内容。

// findByText waits for the element to appear
const username = await screen.findByText('Alice');
expect(username).toBeInTheDocument();

// waitFor wraps assertions that need to wait
await waitFor(() => {
  expect(screen.getByText('3 users')).toBeInTheDocument();
});

为每个测试覆盖处理器

请在测试中使用 server.use() 添加一次性处理器,使其仅覆盖该测试的默认处理器。

test('shows error on API failure', async () => {
  server.use(
    http.get('/api/users', () => {
      return HttpResponse.json({ message: 'Server error' }, { status: 500 });
    })
  );

  render(<UserList />);
  expect(await screen.findByText('Failed to load users')).toBeInTheDocument();
});

测试加载状态

请在渲染后立即(同步地)断言加载指示器,然后再等待异步数据到达。

test('shows loading state initially', () => {
  render(<UserList />);
  expect(screen.getByRole('progressbar')).toBeInTheDocument();
  // or
  expect(screen.getByText('Loading...')).toBeInTheDocument();
});

测试 POST 请求

定义一个 POST 处理程序,用于验证请求正文并返回已创建的资源。断言组件反映成功状态。

server.use(
  http.post('/api/users', async ({ request }) => {
    const body = await request.json();
    return HttpResponse.json({ id: 2, ...body }, { status: 201 });
  })
);

test('creates a user', async () => {
  const user = userEvent.setup();
  render(<NewUserForm />);
  await user.type(screen.getByLabelText('Name'), 'Bob');
  await user.click(screen.getByRole('button', { name: /create/i }));
  expect(await screen.findByText('User created!')).toBeInTheDocument();
});

网络延迟,实现更真实的测试

为处理程序添加人工延迟,以更充分地测试加载界面,并使用 MSW 的 delay 工具。

import { delay } from 'msw';

http.get('/api/users', async () => {
  await delay(200);
  return HttpResponse.json([{ id: 1, name: 'Alice' }]);
})

使用 React Query 进行测试

为每个测试将组件包裹在全新的 QueryClientProvider 中,防止测试之间发生状态泄漏。

function renderWithQuery(ui: React.ReactElement) {
  const queryClient = new QueryClient({
    defaultOptions: { queries: { retry: false } },
  });
  return render(
    <QueryClientProvider client={queryClient}>{ui}</QueryClientProvider>
  );
}

断言请求数据

在处理程序中使用请求监视器,验证应用发送了正确的请求正文或标头。

let capturedBody: unknown;

server.use(
  http.post('/api/login', async ({ request }) => {
    capturedBody = await request.json();
    return HttpResponse.json({ token: 'abc' });
  })
);

test('sends credentials to API', async () => {
  // ... submit form ...
  expect(capturedBody).toEqual({ email: 'a@b.com', password: 'pass' });
});

开发环境中的浏览器端 MSW

MSW 也可以在开发期间运行于浏览器中。运行 npx msw init public/ 来安装服务工作线程,并在 main.tsx 中导入处理程序,以便在本地开发期间使用模拟接口。

快速检查

对于接口调用完成后出现的内容,您应使用哪种 RTL 查询类型进行断言?

回顾

MSW 会拦截真实的网络请求,因此无需访问在线服务器也能让测试更加真实。使用 server.use() 按测试覆盖处理程序,使用 findBy 进行异步断言,并在 React Query 测试中使用全新的 QueryClientProvider 包裹组件。

常见问题解答

「使用 MSW 测试异步界面与 API 调用」课时是免费的吗?

是的 — 「使用 MSW 测试异步界面与 API 调用」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 React Academy 课程的其余内容,请升级到 CoddyKit PRO。 React Academy 课程共包含 4 节课。

「使用 MSW 测试异步界面与 API 调用」这节课中我会学到什么?

使用 Mock Service Worker 模拟 HTTP 请求,测试获取数据的组件。 你通过在浏览器中直接运行的动手代码来练习 React Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 React Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 React Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「使用 MSW 测试异步界面与 API 调用」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 React Academy 课中编写并运行代码吗?

能。每节 React Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 React Testing Library 进行集成测试
  2. 使用 MSW 测试异步界面与 API 调用
  3. Playwright for React 入门
  4. 端到端测试表单与用户流程
← 返回 React Academy