
Playwright Python API 测试实战用 APIRequestContext 测试 REST 接口与验证服务端状态【免费下载链接】playwrightPlaywright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.项目地址: https://gitcode.com/GitHub_Trending/pl/playwright本文基于 Playwright 官方文档 API testing (Python) 编写围绕APIRequestContext这一核心对象展开如何在纯 Python 环境下不启动页面直接发送 HTTP(S) 请求测试 REST API、如何用 API 调用为浏览器测试预置服务端状态、如何在用户操作后通过 API 校验服务端落库结果以及如何借助storage_state在BrowserContext与APIRequestContext之间复用认证状态。读完本文你可以用pytest-playwright搭建一套可运行的 API 测试套件并理解各配置项与响应对象在底层的行为机制。三种典型使用场景Playwright 除了驱动浏览器还可以直接访问应用的 REST API。文档明确列出了三个典型场景直接测试服务端 API不加载页面、不在其中执行 JS纯粹验证接口行为访问 Web 应用前预置服务端状态比如先通过 API 创建好测试数据再打开页面浏览器操作完成后校验服务端后置条件UI 操作结束后用 API 确认数据确实写入服务端。这三类需求均可通过APIRequestContext的方法实现。APIRequestContext自 v1.16 起提供支持发送各种类型的 HTTP(S) 请求get/post/put/delete/patch/head/fetch会自动跟随重定向、从上下文填充请求 Cookie、并用响应中的Set-Cookie更新上下文。一个重要的机制区别值得先明确每个 Playwright 浏览器上下文都关联一个APIRequestContext通过browser_context.request或page.request访问它与BrowserContext共享同一个 Cookie 罐——通过 API 登录会连带登录浏览器而通过playwright.request.new_context()创建的是独立的隔离实例拥有自己独立的 Cookie 存储。本文的 API 测试正是采用后者的独立上下文方式。配置会话级 fixture 设置 baseURL 与鉴权头以下示例以 GitHub API 为测试目标测试套件整体要做三件事测试前创建新仓库、创建若干 issue 并校验服务端状态、测试后删除仓库。GitHub API 需要授权因此文档建议用一个 session 级 fixture 一次性配置好 token 与base_url让后续所有测试的路径都只需写相对路径。这里依赖pytest-playwright提供的playwrightfixture同步 API 版本import os from typing import Generator import pytest from playwright.sync_api import Playwright, APIRequestContext GITHUB_API_TOKEN os.getenv(GITHUB_API_TOKEN) assert GITHUB_API_TOKEN, GITHUB_API_TOKEN is not set pytest.fixture(scopesession) def api_request_context( playwright: Playwright, ) - Generator[APIRequestContext, None, None]: headers { # We set this header per GitHub guidelines. Accept: application/vnd.github.v3json, # Add authorization token to all requests. # Assuming personal access token available in the environment. Authorization: ftoken {GITHUB_API_TOKEN}, } request_context playwright.request.new_context( base_urlhttps://api.github.com, extra_http_headersheaders ) yield request_context request_context.dispose()参数说明依据 APIRequestContext API 文档base_url请求 URL 的基准前缀测试中写/repos/...即可拼接出完整地址extra_http_headers附加到每一个请求上的公共头Accept: application/vnd.github.v3json是 GitHub API 的规范要求Authorization: token PAT携带个人访问令牌request_context.dispose()dispose会释放该上下文及其所有响应占用的内存之后再调用其任何方法都会抛异常——响应体会缓存在内存中以便后续调用response.body()因此显式 dispose 是良好的资源管理习惯。仓库中还提供了一个 JS/TS 版本的同款示例 examples/github-api/tests/test-api.spec.ts其结构与 Python 版本一一对应test.use({ baseURL, extraHTTPHeaders })对应new_context(base_url..., extra_http_headers...)beforeAll/afterAll对应 pytest 的 session fixture。编写 API 测试创建 issue 并校验服务端状态fixture 就绪后测试体非常直接post发送 JSON 数据创建 issue再get拉取 issue 列表做断言import os from typing import Generator import pytest from playwright.sync_api import Playwright, APIRequestContext GITHUB_API_TOKEN os.getenv(GITHUB_API_TOKEN) assert GITHUB_API_TOKEN, GITHUB_API_TOKEN is not set GITHUB_USER os.getenv(GITHUB_USER) assert GITHUB_USER, GITHUB_USER is not set GITHUB_REPO test # ... def test_should_create_bug_report(api_request_context: APIRequestContext) - None: data { title: [Bug] report 1, body: Bug description, } new_issue api_request_context.post(f/repos/{GITHUB_USER}/{GITHUB_REPO}/issues, datadata) assert new_issue.ok issues api_request_context.get(f/repos/{GITHUB_USER}/{GITHUB_REPO}/issues) assert issues.ok issues_response issues.json() issue list(filter(lambda issue: issue[title] [Bug] report 1, issues_response))[0] assert issue assert issue[body] Bug description def test_should_create_feature_request(api_request_context: APIRequestContext) - None: data { title: [Feature] request 1, body: Feature description, } new_issue api_request_context.post(f/repos/{GITHUB_USER}/{GITHUB_REPO}/issues, datadata) assert new_issue.ok issues api_request_context.get(f/repos/{GITHUB_USER}/{GITHUB_REPO}/issues) assert issues.ok issues_response issues.json() issue list(filter(lambda issue: issue[title] [Feature] request 1, issues_response))[0] assert issue assert issue[body] Feature description这里涉及APIResponse对象的几个核心成员response.ok布尔值状态码在 200–299 范围内为Trueresponse.json()将响应体解析为 Python 对象同步 API 下可直接调用异步 API 下需awaitresponse.status/response.statusText状态码与状态文本如 200 / OKresponse.headers响应头字典response.text()、response.body()文本与原始字节体response.url响应最终 URL跟随重定向后。post方法的data参数直接接受 Python 字典Playwright 会将其序列化为 JSON 请求体并自动处理Content-Type若需application/x-www-form-urlencoded表单则改用form参数multipart参数则用于multipart/form-data文件上传。此外每个请求方法还支持paramsURL 查询参数、headers单次请求级覆盖、timeout、fail_on_status_code、ignore_https_errors、max_redirects、max_retries等选项详见 APIRequestContext 方法签名。Setup 与 Teardown会话级 autouse fixture上述测试假设仓库已存在。合理的做法是用一个session 级 fixture在所有测试前创建仓库、测试结束后删除。fixture 中yield之前的部分是 before all之后是 after all# ... pytest.fixture(scopesession, autouseTrue) def create_test_repository( api_request_context: APIRequestContext, ) - Generator[None, None, None]: # Before all new_repo api_request_context.post(/user/repos, data{name: GITHUB_REPO}) assert new_repo.ok yield # After all deleted_repo api_request_context.delete(f/repos/{GITHUB_USER}/{GITHUB_REPO}) assert deleted_repo.okautouseTrue使该 fixture 无需在测试函数参数中声明即可自动生效。注意两个 fixture 的依赖关系create_test_repository依赖api_request_contextpytest 会保证后者先创建。完整测试示例将以上三部分合并得到文档给出的完整可运行示例前置环境变量GITHUB_API_TOKEN与GITHUB_USERfrom enum import auto import os from typing import Generator import pytest from playwright.sync_api import Playwright, Page, APIRequestContext, expect GITHUB_API_TOKEN os.getenv(GITHUB_API_TOKEN) assert GITHUB_API_TOKEN, GITHUB_API_TOKEN is not set GITHUB_USER os.getenv(GITHUB_USER) assert GITHUB_USER, GITHUB_USER is not set GITHUB_REPO test pytest.fixture(scopesession) def api_request_context( playwright: Playwright, ) - Generator[APIRequestContext, None, None]: headers { # We set this header per GitHub guidelines. Accept: application/vnd.github.v3json, # Add authorization token to all requests. # Assuming personal access token available in the environment. Authorization: ftoken {GITHUB_API_TOKEN}, } request_context playwright.request.new_context( base_urlhttps://api.github.com, extra_http_headersheaders ) yield request_context request_context.dispose() pytest.fixture(scopesession, autouseTrue) def create_test_repository( api_request_context: APIRequestContext, ) - Generator[None, None, None]: # Before all new_repo api_request_context.post(/user/repos, data{name: GITHUB_REPO}) assert new_repo.ok yield # After all deleted_repo api_request_context.delete(f/repos/{GITHUB_USER}/{GITHUB_REPO}) assert deleted_repo.ok def test_should_create_bug_report(api_request_context: APIRequestContext) - None: data { title: [Bug] report 1, body: Bug description, } new_issue api_request_context.post( f/repos/{GITHUB_USER}/{GITHUB_REPO}/issues, datadata ) assert new_issue.ok issues api_request_context.get(f/repos/{GITHUB_USER}/{GITHUB_REPO}/issues) assert issues.ok issues_response issues.json() issue list( filter(lambda issue: issue[title] [Bug] report 1, issues_response) )[0] assert issue assert issue[body] Bug description def test_should_create_feature_request(api_request_context: APIRequestContext) - None: data { title: [Feature] request 1, body: Feature description, } new_issue api_request_context.post( f/repos/{GITHUB_USER}/{GITHUB_REPO}/issues, datadata ) assert new_issue.ok issues api_request_context.get(f/repos/{GITHUB_USER}/{GITHUB_REPO}/issues) assert issues.ok issues_response issues.json() issue list( filter(lambda issue: issue[title] [Feature] request 1, issues_response) )[0] assert issue assert issue[body] Feature description该示例在仓库中的 TypeScript 对应版本见 examples/github-api其 playwright.config.ts 展示了forbidOnly、CI 下的retries与workers等常规配置可作为跨语言参考。用 API 预置服务端状态再用 UI 断言API 测试与浏览器测试可以无缝组合。下面的测试先通过 API 连续创建两个 issue然后打开 issue 列表页用LocatorAssertions断言最新创建的排在列表顶部def test_last_created_issue_should_be_first_in_the_list(api_request_context: APIRequestContext, page: Page) - None: def create_issue(title: str) - None: data { title: title, body: Feature description, } new_issue api_request_context.post( f/repos/{GITHUB_USER}/{GITHUB_REPO}/issues, datadata ) assert new_issue.ok create_issue([Feature] request 1) create_issue([Feature] request 2) page.goto(fhttps://github.com/{GITHUB_USER}/{GITHUB_REPO}/issues) first_issue page.locator(a[data-hovercard-typeissue]).first expect(first_issue).to_have_text([Feature] request 2)要点在于两条链路的分工api_request_context独立上下文负责快速、稳定地铺数据pagefixture 负责真实渲染验证。注意此处 API 上下文是隔离的它的 Cookie 不会与page所在浏览器上下文互通——如果需要共享登录态应改用page.request或传递 storage state见下节。浏览器操作后用 API 校验服务端落库与上一步方向相反先通过 UI 完成用户操作再回查 API 确认服务端状态确实变化def test_last_created_issue_should_be_on_the_server(api_request_context: APIRequestContext, page: Page) - None: page.goto(fhttps://github.com/{GITHUB_USER}/{GITHUB_REPO}/issues) page.locator(textNew issue).click() page.locator([aria-labelTitle]).fill(Bug report 1) page.locator([aria-labelComment body]).fill(Bug description) page.locator(textSubmit new issue).click() issue_id page.url.split(/)[-1] new_issue api_request_context.get(fhttps://github.com/{GITHUB_USER}/{GITHUB_REPO}/issues/{issue_id}) assert new_issue.ok assert new_issue.json()[title] [Bug] report 1 assert new_issue.json()[body] Bug description流程细节提交后 GitHub 会导航到新建 issue 的详情页测试从page.url中截取末段作为issue_id随后发起 GET 请求校验服务端存储的title与body。这里演示了UI 操作 → 服务端后置条件校验的完整闭环——仅靠 UI 断言无法确认数据真正持久化而 API 校验恰好补足这一层。复用认证状态storage_state 在两类上下文间互换Web 应用普遍使用基于 Cookie 或 token 的认证认证状态以 Cookie 形式保存。Playwright 提供APIRequestContext.storage_state方法可以从已认证的上下文中取出 storage state再用它创建新的上下文。关键点storage state 在BrowserContext与APIRequestContext之间是可互换的——你可以先用 API 调用完成登录免启动浏览器的快速认证然后把带 Cookie 的状态注入新的浏览器上下文。request_context playwright.request.new_context(http_credentials{username: test, password: test}) request_context.get(https://api.example.com/login) # Save storage state into a variable. state request_context.storage_state() # Create a new context with the saved storage state. context browser.new_context(storage_statestate)storage_state()返回一个包含cookies含name、value、domain、path、expires、httpOnly、secure、sameSite字段与originslocalStorage 快照的对象browser.new_context(storage_state...)则接收同样的结构。反向操作也成立先经浏览器完成登录再browser_context.storage_state()导出供后续APIRequestContext使用从而跳过重复的登录流程。小结与延伸阅读纯 API 测试playwright.request.new_context(base_url..., extra_http_headers...)创建独立上下文session 级 fixture 管理生命周期dispose()释放资源API UI 组合用 API 铺数据、用expect(locator)断言 UI或用 UI 操作后get回查服务端状态认证复用storage_state在浏览器上下文与 API 上下文之间双向流通。可继续在仓库中查阅的资料原始文档docs/src/api-testing-python.md同类文档JS / C# 版本docs/src/api-testing-js.md、docs/src/api-testing-csharp.mdAPI 参考APIRequestContext、APIResponseTS 版 GitHub API 示例examples/github-api/tests/test-api.spec.tsPython 测试运行器pytest-playwright fixture 说明docs/src/running-tests-python.md【免费下载链接】playwrightPlaywright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.项目地址: https://gitcode.com/GitHub_Trending/pl/playwright创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考