Playwright Python API测试实战:从环境搭建到CI/CD集成

发布时间:2026/6/29 9:08:59
Playwright Python API测试实战:从环境搭建到CI/CD集成 1. 项目概述为什么是 Playwright Python 做 API 测试最近在项目里我们团队遇到了一个挺典型的问题前端页面功能迭代飞快后端接口也同步更新但传统的接口测试脚本维护起来越来越吃力。用requests库写吧断言和报告得自己搭用 Postman 做自动化吧又觉得和 CI/CD 流程集成不够丝滑而且复杂场景下的数据准备和清理写起来也麻烦。正好团队里已经在用 Playwright 做 Web UI 自动化了我就琢磨着能不能把这套熟悉的工具链也用到 API 测试上一番折腾下来发现 Playwright 配合 Python 做 API 测试不仅可行而且体验出乎意料的好它把浏览器上下文Browser Context里的网络拦截和监听能力直接开放给了我们让 API 测试也能享受到 Playwright 生态的便利。简单来说Playwright 不再只是一个“浏览器自动化工具”。从某个版本开始它提供了独立的APIRequestContext对象让你能脱离浏览器实例直接发起 HTTP 请求GET, POST, PUT, DELETE 等并且能无缝地使用 Playwright 内置的断言库、Fixture 机制以及强大的测试报告。这意味着如果你已经熟悉了 Playwright 的写法和模式那么 API 测试的学习成本几乎为零。更重要的是你可以在同一个测试项目中混合编写 UI 测试和 API 测试用 API 快速准备测试数据如创建用户、生成订单再用 UI 测试去验证前端展示这种混合测试策略能极大提升测试效率和场景覆盖的深度。所以这篇内容就是把我从零开始搭建这套方案的过程、踩过的坑以及最终沉淀下来的最佳实践完整地分享出来。无论你是正在寻找更优雅 API 测试方案的测试工程师还是已经在使用 Playwright 想拓展其边界的开发者相信都能找到可以直接“抄作业”的干货。2. 环境搭建与核心概念解析2.1 搭建你的测试环境工欲善其事必先利其器。第一步是把环境准备好。这里假设你已经有 Python 环境如果没有去官网下载安装最新稳定版即可过程不赘述。1. 创建虚拟环境与安装 Playwright这是我最推荐的做法为项目创建独立的虚拟环境避免包依赖冲突。# 1. 创建项目目录并进入 mkdir playwright-api-testing cd playwright-api-testing # 2. 创建虚拟环境这里使用 venv你也可以用 conda python -m venv venv # 3. 激活虚拟环境 # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate # 4. 安装 Playwright 的 Python 包 pip install pytest-playwright这里直接安装pytest-playwright它会自动拉取playwright核心库以及pytest插件这是目前最主流的测试运行组合。2. 安装浏览器驱动可选但推荐虽然纯 API 测试不需要启动浏览器但 Playwright 的安装命令会确保所有依赖就位。执行以下命令playwright install这个命令会下载 Chromium, Firefox 和 WebKit 的二进制文件。对于纯 API 测试你可以通过环境变量PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD1来跳过但为了环境完整性和未来可能的混合测试我建议一次性装好。3. 验证安装创建一个简单的 Python 脚本test_env.py来验证import playwright from playwright.sync_api import sync_playwright print(fPlaywright 版本: {playwright.__version__}) with sync_playwright() as p: # 尝试创建一个 API 请求上下文而不启动浏览器 request_context p.request.new_context() print(APIRequestContext 创建成功) request_context.dispose() # 记得释放资源运行python test_env.py如果没有报错并输出版本号说明环境配置成功。注意很多人会疑惑为什么 API 测试还要装浏览器这是因为 Playwright 的设计是统一的。playwright install确保底层通信协议所需的所有组件就绪。即使你不启动浏览器窗口这些组件也是网络请求和拦截功能的基础。跳过安装可能会导致一些高级功能如模拟特定浏览器环境发出的请求头不可用。2.2 理解 Playwright for API 的核心对象在开始写测试之前必须理清几个核心对象这能帮你理解 Playwright API 测试的运作模式避免后续混淆。1.APIRequestContext你的 HTTP 客户端这是 API 测试的绝对核心。你可以把它理解为一个加强版的、会话保持的requests.Session()。它由playwright.request或browser_context.request创建。关键特性包括自动管理 Cookie 和 Header在同一个上下文内发起的请求会自动携带之前响应返回的 Cookie如 session-id模拟真实浏览器会话。内置超时与重试可以在创建时配置全局超时、重试策略比手动为每个requests调用设置更统一。支持代理与 HTTPS 代理配置方式非常直观。便捷的文件上传处理multipart/form-data比requests更简单。2.Playwright与BrowserContextPlaywright: 总入口。通过sync_playwright()或async_playwright()启动。BrowserContext: 浏览器上下文。一个关键点是你可以从一个BrowserContext中获取其关联的APIRequestContext。这样做的好处是这个 API 上下文会共享该浏览器上下文的所有状态比如存储的 Cookie、LocalStorage 以及设置的代理和权限。这对于需要先通过 UI 登录再用相同会话测试 API 的场景极其有用。3.Page与 API 测试的联动虽然纯 API 测试不直接操作Page但 Playwright 允许你在 UI 测试中监听和拦截网络请求。这意味着你可以在 UI 操作过程中断言某个特定的 API 接口被调用且携带了正确的参数。拦截 API 返回修改响应数据以测试前端的不同表现。 这种 UI 与 API 的联动测试是 Playwright 相较于其他单一工具的巨大优势。同步 vs. 异步 APIPlaywright 同时支持同步 (sync_api) 和异步 (async_api) 两种模式。对于大多数 API 测试场景请求是顺序执行的使用同步 API 代码更简洁直观也是本文示例主要采用的方式。如果你的测试框架本身是异步的例如使用pytest-asyncio或者需要高并发地发送大量请求则可以考虑异步模式。3. 从零编写你的第一个 API 测试用例理论讲得再多不如动手写一个。我们以一个典型的 RESTful API —— JSONPlaceholder 一个免费的在线测试 API 服务为例编写一个完整的测试用例。3.1 基础请求GET, POST, PUT, DELETE我们先创建一个测试文件test_basic_api.py。import pytest from playwright.sync_api import sync_playwright, expect # 定义一个基础 URL方便管理 BASE_URL https://jsonplaceholder.typicode.com def test_get_posts(): 测试获取帖子列表 with sync_playwright() as p: # 1. 创建 API 请求上下文可以在这里配置公共参数如超时时间 request_context p.request.new_context( timeout30000, # 30秒超时 extra_http_headers{ Content-Type: application/json, User-Agent: PlaywrightAPITest/1.0 } ) # 2. 发起 GET 请求 response request_context.get(f{BASE_URL}/posts) # 3. 使用 Playwright 内置断言进行验证 # 检查状态码为 200 expect(response).to_be_ok() # 等同于 assert response.status 200 # 检查响应体是 JSON 数组 response_json response.json() assert isinstance(response_json, list) # 检查数组长度大于 0 assert len(response_json) 0 # 检查第一个帖子包含预期的字段 first_post response_json[0] assert id in first_post assert title in first_post assert body in first_post assert userId in first_post # 4. 也可以使用 expect 进行更丰富的断言 expect(first_post).to_have_property(userId, 1) # 5. 记得释放资源在 with 语句结束时会自动调用 dispose但显式调用是好习惯 request_context.dispose() def test_create_post(): 测试创建新帖子 with sync_playwright() as p: request_context p.request.new_context() new_post_data { title: My New Post, body: This is the body of my new post., userId: 1 } # 发起 POST 请求data 参数会自动被序列化为 JSON因为设置了Content-Type response request_context.post( f{BASE_URL}/posts, datanew_post_data ) expect(response).to_be_ok() created_post response.json() # 验证返回的数据包含了我们发送的数据 assert created_post[title] new_post_data[title] assert created_post[body] new_post_data[body] assert created_post[userId] new_post_data[userId] # 服务器通常会生成一个 id assert created_post[id] is not None request_context.dispose() def test_update_post(): 测试更新帖子PUT with sync_playwright() as p: request_context p.request.new_context() update_data { id: 1, title: Updated Title, body: Updated body content., userId: 1 } response request_context.put( f{BASE_URL}/posts/1, dataupdate_data ) expect(response).to_be_ok() updated_post response.json() assert updated_post[title] Updated Title request_context.dispose() def test_delete_post(): 测试删除帖子 with sync_playwright() as p: request_context p.request.new_context() response request_context.delete(f{BASE_URL}/posts/1) # 删除成功通常返回 200 或 204 expect(response).to_be_ok() # 或 assert response.status in [200, 204] request_context.dispose()运行测试pytest test_basic_api.py -v。你应该能看到四个测试用例全部通过。这就是一个最基础的 API 测试套件了。实操心得request.new_context()创建的上下文是相互独立的。这意味着test_get_posts和test_create_post中的请求不会共享 Cookie。如果你需要会话保持需要在创建上下文时手动设置相同的存储状态或者使用同一个上下文对象。在真实的项目测试中我通常会创建一个Fixture来提供配置好的、可重用的请求上下文这是下一节的重点。3.2 使用 Pytest Fixture 优化测试结构上面的例子每个测试函数都重复了创建和销毁APIRequestContext的代码这违反了 DRYDon‘t Repeat Yourself原则。Pytest 的 Fixture 机制是解决这个问题的完美工具。我们来重构一下。创建conftest.py文件这是 Pytest 的配置文件其中定义的 Fixture 可以被同一目录及子目录下的所有测试文件使用。# conftest.py import pytest from playwright.sync_api import sync_playwright pytest.fixture(scopesession) def api_request_context(): 创建一个会话级别的 API 请求上下文。 scopesession 表示整个测试会话只创建一次所有测试共用。 适用于测试接口无状态或依赖独立测试数据的场景。 如果测试需要隔离的会话如不同用户登录请使用 scopefunction。 with sync_playwright() as p: # 在这里可以进行全局配置如基础URL、默认请求头、代理等 context p.request.new_context( base_urlhttps://jsonplaceholder.typicode.com, # 设置基础URL后续请求可以用相对路径 extra_http_headers{ Content-Type: application/json, User-Agent: PlaywrightAPITest-Framework/1.0 }, timeout60000 # 全局超时设置 ) yield context # 将上下文提供给测试函数使用 context.dispose() # 所有测试结束后清理上下文 pytest.fixture def unique_post_data(): 提供一个唯一的帖子数据避免测试间因数据冲突而失败 import time return { title: fTest Post {int(time.time())}, # 使用时间戳确保唯一性 body: This is a unique test post body., userId: 1 }然后我们更新测试文件test_with_fixture.pyimport pytest from playwright.sync_api import expect def test_get_posts_with_fixture(api_request_context): 使用 Fixture 获取帖子列表 # 直接使用 fixture 注入的请求上下文 response api_request_context.get(/posts) # 使用相对路径因为 base_url 已在 fixture 中设置 expect(response).to_be_ok() posts response.json() assert len(posts) 0 def test_create_and_verify_post(api_request_context, unique_post_data): 测试创建帖子并立即查询验证 # 1. 创建帖子 create_response api_request_context.post(/posts, dataunique_post_data) expect(create_response).to_be_ok() created_post create_response.json() created_post_id created_post[id] # 2. 使用 GET 查询刚创建的帖子 get_response api_request_context.get(f/posts/{created_post_id}) expect(get_response).to_be_ok() fetched_post get_response.json() # 3. 验证数据一致性 assert fetched_post[title] unique_post_data[title] assert fetched_post[body] unique_post_data[body] def test_unsuccessful_request(api_request_context): 测试一个预期会失败的请求如资源不存在 # 请求一个不存在的帖子 ID response api_request_context.get(/posts/99999) # 断言状态码是 404 assert response.status 404 # 或者使用 expect # expect(response).to_have_status(404) # 可以进一步检查错误响应体 error_body response.json() # 根据 API 设计这里可能是一个空对象或包含错误信息 # assert error_body {}运行pytest test_with_fixture.py -v。你会发现代码简洁多了而且有了base_url的配置请求 URL 也更清晰。unique_post_datafixture 确保了每次测试的数据独立性避免了测试污染。注意事项scopesession的 Fixture 虽然高效但要小心使用。如果多个测试用例修改了共享资源比如都去修改同一条数据可能会相互干扰导致测试结果不稳定。对于有状态操作的 API 测试更安全的做法是使用scopefunction默认值或者确保每个测试用例都创建和清理自己独有的测试数据。4. 高级特性与实战技巧掌握了基础之后我们来看看 Playwright API Testing 那些能真正提升效率和测试深度的特性。4.1 处理认证与授权大多数 API 都需要认证。Playwright 的APIRequestContext可以很方便地处理多种认证方式。1. Bearer Token (JWT)这是目前最常见的 API 认证方式。你可以在创建上下文时设置全局 Header。# 在 conftest.py 的 fixture 中 pytest.fixture(scopefunction) # 每个测试函数一个上下文避免 token 混淆 def authenticated_context(): with sync_playwright() as p: # 假设我们有一个获取 token 的函数在实际项目中可能来自环境变量或登录接口 token obtain_auth_token() context p.request.new_context( base_urlhttps://api.yourservice.com, extra_http_headers{ Authorization: fBearer {token}, Content-Type: application/json } ) yield context context.dispose() # 在测试中 def test_access_protected_resource(authenticated_context): response authenticated_context.get(/v1/protected/data) expect(response).to_be_ok()2. Basic Authcontext p.request.new_context( base_urlhttps://api.example.com, # Playwright 的 http_credentials 是给浏览器用的对于 API 上下文直接设置 Header 更直接 extra_http_headers{ Authorization: Basic base64.b64encode(f{username}:{password}.encode()).decode() } )3. API Key通常放在 Header 或 Query 参数中。# 放在 Header 中 context p.request.new_context( extra_http_headers{X-API-Key: your-secret-api-key-here} ) # 或者作为查询参数注意这通常安全性较低因为参数可能被日志记录 # response context.get(/endpoint?api_keyyour-key)4.2 文件上传与下载文件上传Playwright 处理multipart/form-data非常优雅。def test_upload_avatar(api_request_context): # 准备文件路径 file_path ./test_data/avatar.png # 使用 multipart 参数 response api_request_context.post( /user/avatar, multipart{ avatar: open(file_path, rb), # 文件对象 userId: 123 # 其他表单字段 } ) expect(response).to_be_ok()文件下载API 可能返回一个文件流。Playwright 的响应对象提供了body()方法来获取原始字节或者save_as()方法直接保存。def test_download_report(api_request_context): response api_request_context.get(/reports/monthly.pdf) expect(response).to_be_ok() # 方法1保存到文件 download_path ./downloads/monthly_report.pdf response.save_as(download_path) assert os.path.exists(download_path) # 方法2获取字节内容进行校验 # pdf_body response.body() # assert pdf_body.startswith(b%PDF) # 简单验证文件头4.3 模拟与拦截网络请求这是 Playwright 的杀手级功能之一在 API 测试中同样威力巨大。你可以拦截从 API 上下文发出的请求或者拦截到达 API 上下文的响应。场景1修改请求参数例如注入一个测试标记def test_with_request_interception(api_request_context): # 启动请求拦截 api_request_context.route(**/api/data, lambda route: route.continue_(headers{ **route.request.headers, X-Test-Env: playwright # 添加一个自定义头 })) response api_request_context.get(/api/data) # 此时发出的请求会携带 X-Test-Env 头场景2模拟MockAPI 响应用于测试前端或服务对特定响应的处理。def test_mock_error_response(api_request_context): # 拦截特定请求并返回一个模拟的失败响应 api_request_context.route( **/api/unstable-endpoint, lambda route: route.fulfill( status500, content_typeapplication/json, bodyjson.dumps({error: Internal Server Error, code: ERR_500}) ) ) # 现在调用这个接口会立刻得到我们模拟的500错误而不是真正的服务响应 response api_request_context.get(/api/unstable-endpoint) assert response.status 500 assert response.json()[code] ERR_500这个功能在以下情况特别有用后端接口尚未开发完成但前端测试需要依赖。测试一些难以触发的错误场景如超时、特定错误码。避免在测试中调用外部、不稳定或收费的第三方服务。4.4 性能测试与并发请求虽然 Playwright 不是专业的压测工具如 Locust, JMeter但其异步 API 和请求上下文依然可以用于简单的并发测试或验证接口在并发下的行为。import asyncio from playwright.async_api import async_playwright async def test_concurrent_requests(): 使用异步 API 发送并发请求 async with async_playwright() as p: context await p.request.new_context() # 定义要并发请求的 URL 列表 urls [f/posts/{i} for i in range(1, 6)] # 创建任务列表 tasks [context.get(url) for url in urls] # 并发执行所有 GET 请求 responses await asyncio.gather(*tasks) # 验证所有请求都成功 for response in responses: assert response.status 200 print(await response.json()) await context.dispose() # 在 pytest 中运行异步测试需要 pytest-asyncio 插件 pytest.mark.asyncio async def test_concurrent_in_pytest(): await test_concurrent_requests()5. 集成到 CI/CD 与生成测试报告自动化测试只有集成到持续集成/持续部署CI/CD流水线中才能最大化其价值。同时清晰的测试报告对于问题定位和团队协作至关重要。5.1 使用 Pytest 运行测试并生成报告Playwright 的 Python 测试本质上就是 Pytest 测试因此可以无缝使用 Pytest 丰富的插件生态。1. 常用运行命令# 运行所有测试 pytest # 运行特定目录或文件 pytest tests/api/ # 运行包含特定关键词的测试 pytest -k create or delete # 遇到第一个失败就停止 pytest -x # 并行运行测试需要 pytest-xdist pytest -n auto2. 生成 HTML 测试报告使用pytest-html插件可以生成美观的 HTML 报告。# 安装插件 pip install pytest-html # 运行测试并生成报告 pytest --htmlreport.html --self-contained-html生成的report.html文件会包含测试通过/失败的状态、耗时、错误信息等可以直接在浏览器中打开查看。3. 与 Playwright 原生报告结合Playwright Test 本身也支持多种报告格式如 HTML, JSON, JUnit。虽然我们主要用pytest运行器但可以通过pytest-playwright插件配置。 在pytest.ini或pyproject.toml中配置# pytest.ini [pytest] # 添加 Playwright 相关的配置 addopts --tbshort # 简化错误回溯 --playwright-reporthtml # 生成 Playwright HTML 报告需要插件支持 --junitxmljunit-report.xml # 生成 JUnit 格式报告便于 Jenkins 等 CI 工具集成5.2 在 GitHub Actions 中运行 API 测试下面是一个简单的 GitHub Actions 工作流配置文件.github/workflows/api-tests.yml用于在每次推送代码或发起拉取请求时自动运行测试。name: API Tests with Playwright on: [push, pull_request] jobs: test: runs-on: ubuntu-latest strategy: matrix: python-version: [3.9, 3.10, 3.11] # 测试多个 Python 版本 steps: - uses: actions/checkoutv3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-pythonv4 with: python-version: ${{ matrix.python-version }} - name: Install system dependencies (for Playwright browsers) run: | sudo apt-get update sudo apt-get install -y libwoff1 libopus0 libwebpdemux2 libharfbuzz-icu0 - name: Install Python dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt # 你的依赖文件 pip install pytest-playwright pytest-html pytest-xdist - name: Install Playwright browsers run: playwright install --with-deps chromium # 只安装 Chromium 以加快速度 - name: Run API tests run: | pytest tests/ \ --htmlgithub-actions-report.html \ --junitxmljunit-${{ matrix.python-version }}.xml \ -n auto - name: Upload test report (HTML) if: always() # 即使测试失败也上传报告 uses: actions/upload-artifactv3 with: name: api-test-report-${{ matrix.python-version }} path: github-actions-report.html - name: Upload JUnit test results if: always() uses: actions/upload-artifactv3 with: name: junit-results-${{ matrix.python-version }} path: junit-${{ matrix.python-version }}.xml这个工作流会设置 Python 环境。安装必要的系统库和 Python 包。安装 Playwright 的 Chromium 浏览器对于纯 API 测试可以尝试跳过但为了环境一致性建议安装。并行运行测试并生成 HTML 和 JUnit 格式的报告。将报告作为构件Artifact上传供后续下载查看。踩坑记录在 CI 环境中特别是使用pytest-xdist并行运行时要特别注意测试的独立性和幂等性。确保每个测试用例不依赖其他测试产生的数据并且可以重复运行而不冲突。善用setup_method/teardown_method或者更灵活的 Pytest Fixture如scope”function”来为每个测试创建干净的上下文和测试数据。6. 常见问题排查与调试技巧即使方案再完善实际编写和运行测试时也难免遇到问题。这里分享一些我经常用到的排查技巧。6.1 请求失败或响应不符合预期1. 启用详细日志Playwright 提供了丰富的日志功能可以帮助你看到底层的 HTTP 交互。import logging import sys # 设置 Playwright 的日志级别为 DEBUG logging.basicConfig(levellogging.DEBUG, streamsys.stdout) # 或者在创建上下文时启用调试 context p.request.new_context( # ... 其他配置 ... # 这个参数会打印所有请求和响应注意可能包含敏感信息如token # record_har_pathnetwork_log.har # 更推荐使用 HAR 记录 )更安全有效的方式是使用HARHTTP Archive记录。HAR 文件可以用浏览器开发者工具或专门的 HAR 查看器如 HAR Viewer 打开直观地分析请求和响应。context p.request.new_context(record_har_pathtest.har) # ... 执行你的测试 ... context.dispose() # 测试结束后test.har 文件中就包含了所有网络活动的详细记录。2. 检查请求头和请求体很多时候问题出在请求的细节上。确保你的请求头如Content-Type,Authorization和请求体格式JSON, Form Data完全符合 API 文档的要求。使用 HAR 记录或打印response.request对象来检查实际发出的请求。response context.post(/endpoint, data{key: value}) print(fRequest URL: {response.request.url}) print(fRequest Headers: {response.request.headers}) print(fRequest Body: {response.request.post_data}) # 对于 POST 请求 print(fResponse Status: {response.status}) print(fResponse Headers: {response.headers}) print(fResponse Body: {response.text()[:500]}) # 打印前500个字符3. 处理 SSL 证书问题在测试内部或自签名的 HTTPS 服务时可能会遇到证书错误。context p.request.new_context(ignore_https_errorsTrue) # 忽略所有 HTTPS 错误不推荐用于生产环境测试 # 或者更安全地指定自定义 CA 证书 # context p.request.new_context(ignore_https_errorsFalse, ssl_certpath/to/cert.pem)6.2 测试稳定性与 flaky tests不稳定的测试时好时坏是自动化测试的噩梦。对于 API 测试常见原因和解决方案如下问题原因解决方案网络波动或外部服务不稳定1.增加重试机制使用pytest-rerunfailures插件为不稳定的测试标记重试 (pytest.mark.flaky(reruns3))。2.设置合理的超时在new_context()和具体请求中配置更长的timeout。3.使用 Mock/Stub对于第三方依赖使用route.fulfill进行模拟。测试数据冲突1.使用唯一标识如用时间戳、UUID 生成测试数据如前文的unique_post_datafixture。2.严格的测试隔离每个测试用例都应有独立的setup和teardown创建专属数据并在测试后清理。异步操作或响应延迟1.使用 Playwright 的等待虽然 API 上下文没有page.wait_for_timeout但你可以用time.sleep谨慎使用或更好的方式——轮询查询结果直到满足条件。状态残留1.使用scope”function”的 Fixture确保每个测试有独立的请求上下文。2.在 Fixture 的teardown中清理对于有状态的服务在测试结束后调用清理接口。示例实现一个简单的轮询等待import time def wait_for_condition(api_context, check_func, max_attempts10, interval1): 轮询等待某个条件成立 for attempt in range(max_attempts): if check_func(api_context): return True time.sleep(interval) raise TimeoutError(fCondition not met after {max_attempts} attempts) def test_async_operation(api_request_context): # 触发一个异步任务 start_response api_request_context.post(/async-tasks, data{type: report}) task_id start_response.json()[taskId] # 定义检查任务是否完成的函数 def is_task_complete(ctx): status_resp ctx.get(f/async-tasks/{task_id}) return status_resp.json()[status] COMPLETED # 轮询等待任务完成 wait_for_condition(api_request_context, is_task_complete, max_attempts30, interval2) # 任务完成后获取结果 result_response api_request_context.get(f/async-tasks/{task_id}/result) expect(result_response).to_be_ok()6.3 性能与资源管理当测试套件变得庞大时需要注意资源管理。复用请求上下文对于无状态或只读的测试使用scope”session”的 Fixture 创建一次请求上下文并复用可以避免重复建立连接的开销。及时清理确保在测试结束后调用context.dispose()或使用with语句自动管理释放网络连接等资源。避免内存泄漏如果你在测试中手动创建了大量临时对象如从响应中解析大文件注意在适当的时候释放引用。虽然 Python 有垃圾回收但显式地del大对象或使用生成器处理流式响应是好的实践。监控测试耗时使用pytest的--durations参数找出运行最慢的测试并分析是否有优化空间如减少不必要的请求、合并断言等。pytest --durations10 # 显示最慢的10个测试从简单的requests脚本迁移到基于 Playwright 的测试框架初期可能会觉得多了一些“仪式感”但一旦框架搭建成型其带来的可维护性、可扩展性以及与 UI 测试的协同能力会让你觉得这些投入非常值得。我最深的体会是将 API 测试也纳入 Playwright 的生态后测试代码的风格、工具链和最佳实践得到了统一无论是写 UI 测试的同事还是写 API 测试的同事现在都能看懂的对方的代码复用相同的 Fixture 和工具函数团队协作的效率提升了一个档次。最后分享一个小技巧善用pytest.ini配置文件来管理你的测试默认行为比如默认的标记、路径、命令行参数等。这能让团队所有成员运行测试的方式保持一致减少因环境或命令差异导致的问题。