Playwright Python 教程:高级篇
文章目录
- **目标**
- **一、网络拦截与模拟(Network Interception & Mocking)**
- **1. 基本请求/响应拦截**
- **2. 根据条件修改响应**
- **3. 模拟网络错误**
- **二、认证与持久化状态**
- **1. 保存和恢复认证状态**
- **2. 多用户场景测试**
- **三、高级浏览器配置**
- **1. 模拟设备和地理位置**
- **2. 代理设置**
- **四、录制视频与追踪**
- **1. 录制测试视频**
- **2. 使用追踪记录**
- **五、与 Pytest 集成**
- **1. 基本 Pytest 集成**
- **2. 使用 Pytest Fixtures**
- **3. 参数化测试**
- **六、实战:完整的端到端测试示例**
- **高级篇总结**
- **最佳实践建议**
目标
本篇将带你探索 Playwright 的高级功能,让你能够构建更加专业、强大和高效的自动化测试解决方案。我们将涵盖网络拦截、认证持久化、高级配置、视频录制以及与测试框架的集成。
一、网络拦截与模拟(Network Interception & Mocking)
Playwright 允许你拦截和修改网络请求,这对于模拟 API 响应、测试错误处理或减少对外部服务的依赖非常有用。
1. 基本请求/响应拦截
from playwright.sync_api import sync_playwrightdef test_api_interception():with sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()# 启用请求拦截page.route("**/api/users", lambda route: route.fulfill(status=200,content_type="application/json",body='{"id": 123, "name": "Mock User"}'))page.goto("https://example.com/user-profile")# 此时页面对 /api/users 的请求将返回我们模拟的数据page.click("#refresh-user")browser.close()
2. 根据条件修改响应
def test_conditional_interception():with sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()def handle_route(route):if "api/items" in route.request.url:# 修改响应route.fulfill(status=200,body='[{"id": 1, "name": "Mock Item"}]')else:# 继续正常请求route.continue_()# 注册路由处理程序page.route("**/*", handle_route)page.goto("https://example.com/items")browser.close()
3. 模拟网络错误
def test_network_failure():with sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()# 模拟网络错误page.route("**/api/data", lambda route: route.abort())page.goto("https://example.com/data-page")# 验证错误处理assert page.is_visible("text=Failed to load data")browser.close()
二、认证与持久化状态
1. 保存和恢复认证状态
import os
from playwright.sync_api import sync_playwrightdef test_auth_persistence():with sync_playwright() as p:browser = p.chromium.launch(headless=False)context = browser.new_context()page = context.new_page()# 执行登录操作page.goto("https://example.com/login")page.fill("#username", "testuser")page.fill("#password", "testpass")page.click("#login-btn")# 等待登录完成page.wait_for_url("**/dashboard")# 保存认证状态到文件context.storage_state(path="auth_state.json")browser.close()def test_using_saved_auth():with sync_playwright() as p:browser = p.chromium.launch(headless=False)# 使用保存的认证状态创建上下文context = browser.new_context(storage_state="auth_state.json")page = context.new_page()# 直接访问需要认证的页面page.goto("https://example.com/dashboard")# 验证已登录状态assert page.is_visible("text=Welcome, testuser")browser.close()
2. 多用户场景测试
def test_multiple_users():with sync_playwright() as p:browser = p.chromium.launch(headless=False)# 创建两个独立的上下文(模拟两个用户)user1_context = browser.new_context()user1_page = user1_context.new_page()user2_context = browser.new_context()user2_page = user2_context.new_page()# 用户1登录user1_page.goto("https://example.com/login")user1_page.fill("#username", "user1")user1_page.fill("#password", "pass1")user1_page.click("#login-btn")user1_page.wait_for_url("**/dashboard")# 用户2登录user2_page.goto("https://example.com/login")user2_page.fill("#username", "user2")user2_page.fill("#password", "pass2")user2_page.click("#login-btn")user2_page.wait_for_url("**/dashboard")# 验证两个用户独立会话assert user1_page.is_visible("text=Welcome, user1")assert user2_page.is_visible("text=Welcome, user2")browser.close()
三、高级浏览器配置
1. 模拟设备和地理位置
def test_device_simulation():with sync_playwright() as p:# 使用预定义的设备配置(如 iPhone 11)iPhone_11 = p.devices["iPhone 11"]browser = p.chromium.launch(headless=False)# 创建带有设备模拟的上下文context = browser.new_context(**iPhone_11)page = context.new_page()page.goto("https://example.com")# 验证移动视图assert page.viewport_size["width"] == 414 # iPhone 11 宽度browser.close()def test_geolocation():with sync_playwright() as p:browser = p.chromium.launch(headless=False)# 设置地理位置和权限context = browser.new_context(geolocation={"longitude": 116.397128, "latitude": 39.916527}, # 北京permissions=["geolocation"])page = context.new_page()page.goto("https://maps.example.com")# 触发地理位置请求page.click("#get-location")# 验证位置相关功能assert page.is_visible("text=Beijing")browser.close()
2. 代理设置
def test_with_proxy():with sync_playwright() as p:browser = p.chromium.launch(headless=False,proxy={"server": "http://myproxy.com:8080","username": "user","password": "pass"})context = browser.new_context()page = context.new_page()page.goto("https://example.com")# 验证页面加载成功assert page.title() == "Example Domain"browser.close()
四、录制视频与追踪
1. 录制测试视频
def test_with_video_recording():with sync_playwright() as p:browser = p.chromium.launch(headless=False)# 启用视频录制context = browser.new_context(record_video_dir="videos/")page = context.new_page()# 执行测试操作page.goto("https://example.com")page.click("a")page.wait_for_timeout(1000)# 关闭上下文会自动保存视频context.close()browser.close()
2. 使用追踪记录
def test_with_tracing():with sync_playwright() as p:browser = p.chromium.launch(headless=False)context = browser.new_context()# 开始追踪context.tracing.start(screenshots=True, snapshots=True)page = context.new_page()page.goto("https://example.com")page.click("a")# 停止追踪并保存context.tracing.stop(path="trace.zip")browser.close()# 查看追踪记录
# 使用命令: playwright show-trace trace.zip
五、与 Pytest 集成
1. 基本 Pytest 集成
# test_example.py
import pytest
from playwright.sync_api import Page, expectdef test_example_page(page: Page):page.goto("https://example.com")expect(page).to_have_title("Example Domain")def test_login(page: Page):page.goto("https://example.com/login")page.fill("#username", "testuser")page.fill("#password", "testpass")page.click("#login-btn")expect(page).to_have_url("**/dashboard")
2. 使用 Pytest Fixtures
# conftest.py
import pytest
from playwright.sync_api import Playwright, Browser, BrowserContext@pytest.fixture(scope="session")
def browser(playwright: Playwright):# 启动浏览器(会话级别,所有测试共享)browser = playwright.chromium.launch(headless=False)yield browserbrowser.close()@pytest.fixture
def context(browser: Browser):# 为每个测试创建新的上下文context = browser.new_context()yield contextcontext.close()@pytest.fixture
def page(context: BrowserContext):# 为每个测试创建新的页面page = context.new_page()yield pagepage.close()# test_with_fixtures.py
def test_with_fixtures(page):page.goto("https://example.com")assert page.title() == "Example Domain"
3. 参数化测试
import pytest@pytest.mark.parametrize("username,password,expected", [("correct", "correct", True),("wrong", "correct", False),("correct", "wrong", False),
])
def test_login_combinations(page, username, password, expected):page.goto("https://example.com/login")page.fill("#username", username)page.fill("#password", password)page.click("#login-btn")if expected:expect(page).to_have_url("**/dashboard")else:expect(page).to_have_url("**/login")expect(page).to_have_text("Invalid credentials")
六、实战:完整的端到端测试示例
import pytest
from playwright.sync_api import Page, expectdef test_complete_ecommerce_flow(page: Page):# 1. 浏览产品page.goto("https://demo-shop.example.com")expect(page).to_have_title("Demo Shop")# 2. 搜索产品page.fill("#search-input", "laptop")page.click("#search-button")expect(page).to_have_url("**/search?q=laptop")# 3. 查看产品详情page.click(".product-item:first-child")expect(page).to_have_url("**/product/")# 4. 添加到购物车page.click("#add-to-cart")expect(page.locator("#cart-count")).to_have_text("1")# 5. 查看购物车page.click("#view-cart")expect(page).to_have_url("**/cart")# 6. 结账page.click("#checkout")expect(page).to_have_url("**/checkout")# 7. 填写配送信息page.fill("#name", "John Doe")page.fill("#address", "123 Main St")page.fill("#city", "Anytown")page.select_option("#country", "US")page.click("#continue-to-payment")# 8. 填写支付信息(使用模拟)page.route("**/api/payment", lambda route: route.fulfill(status=200,body='{"success": true, "transactionId": "12345"}'))page.fill("#card-number", "4242424242424242")page.fill("#expiry", "12/25")page.fill("#cvv", "123")page.click("#complete-purchase")# 9. 验证订单确认expect(page).to_have_url("**/order-confirmation")expect(page).to_have_text("Thank you for your order!")
高级篇总结
通过本篇学习,你已经掌握了 Playwright 的高级功能:
- 网络拦截与模拟:能够拦截和修改网络请求,实现 API 模拟和错误测试。
- 认证持久化:保存和恢复登录状态,提高测试效率。
- 高级浏览器配置:模拟设备、地理位置和代理设置。
- 录制与追踪:录制测试视频和使用追踪功能进行调试。
- Pytest 集成:使用行业标准测试框架组织测试用例。
这些高级技能将使你能够构建更加专业、可靠和高效的自动化测试解决方案。
最佳实践建议
- 保持测试独立:每个测试应该能够独立运行,不依赖其他测试的状态。
- 使用页面对象模式:将页面元素和操作封装成类,提高代码可维护性。
- 合理使用等待:优先使用 Playwright 的自动等待和显式等待,避免固定等待。
- 定期维护选择器:随着前端代码变化,定期更新和维护元素选择器。
- 并行执行测试:利用 Playwright 的并行执行能力加快测试速度。