API 测试直接发起请求 request
本教程共 59 篇 · 第 34 篇 · 更新于 2026-08-04 · 约 12 分钟阅读
34. API 测试直接发起请求 request
本节目标:学完能直接用 Playwright 给后端发 HTTP 请求做接口测试,不打开浏览器也能验证服务端逻辑。
有些验证逻辑,根本不需要开浏览器。比如「创建一条数据,再查回来确认存在」,纯后端的事。Playwright 自带一个 request 夹具(Fixture),让你在 Node 里直接发请求。
为什么直接测接口
浏览器测试重在「界面表现得对不对」,接口测试重在「数据对不对」。两者互补。直接发请求的几点好处:
- 速度快,没有页面渲染开销。
- 能在 UI 测试前搭好服务端状态(比如先造一条数据)。
- 能在 UI 操作后校验数据库侧的真实结果。
Note这套能力由
APIRequestContext(API 请求上下文)提供,测试里的request夹具就是它的一个实例。关键一点:它完全不依赖浏览器。一个测试里只注入
request、不注入page,Playwright 压根不会启动浏览器进程。所以纯接口测试跑起来是秒级的。
先配好公共项
接口通常要鉴权和统一域名。在配置里一次性写好,测试里就省心了:
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
baseURL: 'https://api.github.com', // 所有请求都发往这里
extraHTTPHeaders: {
'Accept': 'application/vnd.github.v3+json',
'Authorization': `token ${process.env.API_TOKEN}`, // 鉴权令牌
},
},
});
写一个接口测试
下面用 GitHub 接口演示:创建 issue,再查列表确认它真的进去了。
import { test, expect } from '@playwright/test';
const REPO = 'test-repo-1';
const USER = 'github-username';
test('能创建一条 bug 报告', async ({ request }) => {
const newIssue = await request.post(`/repos/${USER}/${REPO}/issues`, {
data: { title: '[Bug] report 1', body: 'Bug description' },
});
expect(newIssue.ok()).toBeTruthy(); // 创建成功
const issues = await request.get(`/repos/${USER}/${REPO}/issues`);
expect(issues.ok()).toBeTruthy();
expect(await issues.json()).toContainEqual(
expect.objectContaining({ title: '[Bug] report 1' })
);
});
Tip
request会读配置里的baseURL,所以路径写相对地址/repos/...即可,不用写全 URL。
用 beforeAll / afterAll 管前后置
接口测试常需要先建资源、最后销毁。用钩子包起来:
test.beforeAll(async ({ request }) => {
const response = await request.post('/user/repos', { data: { name: REPO } });
expect(response.ok()).toBeTruthy();
});
test.afterAll(async ({ request }) => {
const response = await request.delete(`/repos/${USER}/${REPO}`);
expect(response.ok()).toBeTruthy();
});
在 UI 测试里调接口
request 还能混在界面测试里用。比如先用接口造数据,再去页面确认它排在最前:
import { test, expect, type APIRequestContext } from '@playwright/test';
let apiContext: APIRequestContext;
test.beforeAll(async ({ playwright }) => {
apiContext = await playwright.request.newContext({
baseURL: 'https://api.github.com',
extraHTTPHeaders: { 'Authorization': `token ${process.env.API_TOKEN}` },
});
});
test.afterAll(async () => {
await apiContext.dispose(); // 用完释放
});
test('最新创建的 issue 排在最前', async ({ page }) => {
await apiContext.post(`/repos/${USER}/${REPO}/issues`, {
data: { title: '[Feature] request 1' },
});
await page.goto(`https://github.com/${USER}/${REPO}/issues`);
const firstIssue = page.locator(`a[data-hovercard-type='issue']`).first();
await expect(firstIssue).toHaveText('[Feature] request 1');
});
验证后置条件
接口测试最有价值的地方,是校验「操作后服务端到底变了没有」。比如界面上提交了一张订单,你可以用接口把它查回来,确认它真的落库了,而不只是界面显示成功。
test('提交后服务端有这条记录', async ({ page, request }) => {
await page.goto('/orders/new');
await page.getByLabel('名称').fill('测试订单');
await page.getByText('提交').click();
const id = new URL(page.url()).pathname.split('/').pop();
const resp = await request.get(`/api/orders/${id}`);
expect(resp.ok()).toBeTruthy();
expect(await resp.json()).toMatchObject({ name: '测试订单' });
});
这种「界面操作 + 接口校验」的组合,比单纯看界面更让人放心。
和浏览器共享登录态
request 有两种来源,行为差别很大:
- 测试里注入的
request夹具:挂在同一个 browser context 上,和浏览器共享 cookie。浏览器登录了,它也是登录态。 - 自己
newContext()建的:cookie 完全隔离,谁也不认谁。
最妙的是,你可以用接口登录,把状态存下来,再交给浏览器用:
// 注意:这里的 request 是从包里导入的 APIRequest 对象,不是测试夹具
import { request, chromium } from '@playwright/test';
const requestContext = await request.newContext({
httpCredentials: { username: 'user', password: 'passwd' },
});
await requestContext.get('https://api.example.com/login');
await requestContext.storageState({ path: 'state.json' }); // 存登录态
await requestContext.dispose();
// 浏览器直接带着这个登录态打开
const browser = await chromium.launch();
const context = await browser.newContext({ storageState: 'state.json' });
Warning别把两个
request搞混。测试函数参数里解构出来的request是夹具,没有newContext()方法;能建新上下文的那个request,要么从@playwright/test导入,要么走playwright夹具拿playwright.request。
Note
APIRequestContext这套能力 Python 版同样具备,只是导入方式、命名风格和夹具的组织方式不一样。想看 Python 版怎么写,请见第 57 章,本章只讲 TypeScript。
什么时候该直接测接口
我的原则:纯数据逻辑用接口测,又快又准;涉及界面交互、文案、样式的,还是得开浏览器。
两者顺着一条测试链路串起来,前后端都覆盖,才是最稳的写法。
小结
request夹具背后是APIRequestContext,不启动浏览器,纯接口测试速度极快。- 公共项写进配置:
baseURL定域名,extraHTTPHeaders放鉴权头,测试里就能用相对路径。 - 断言用
response.ok()/response.status(),取数据用await response.json()。 - 前后置资源用
test.beforeAll/test.afterAll建和删,别让测试数据堆积。 - 「接口造数据 + 界面验展示」「界面操作 + 接口验落库」,这两套组合最实用。
- 夹具版
request和浏览器共享 cookie;newContext()建的是隔离的,两者别混用。 - 接口登录拿到的 storageState 可以直接喂给浏览器,省掉走界面登录。
下一章解决一个前置问题:测试要访问的那个本地服务,怎么让它自己起来。