Playwright 1.44 多浏览器上下文实战:1个实例并发执行3种设备模拟测试
📅 2026/7/13 5:13:05
👁️ 阅读次数
📝 编程学习
Playwright 1.44 多浏览器上下文实战:1个实例并发执行3种设备模拟测试
现代Web应用需要适配从手机到桌面端的各类设备,传统测试方案往往需要为每种设备单独编写测试脚本,不仅效率低下,还难以保证测试环境的一致性。Playwright的浏览器上下文(BrowserContext)功能彻底改变了这一局面——它允许我们在单个浏览器实例中创建多个完全隔离的测试环境,每个环境可以独立配置设备参数、网络条件和存储状态。
1. 浏览器上下文的核心价值
浏览器上下文是Playwright最强大的设计之一,它相当于一个轻量级的浏览器会话,具有以下特性:
- 完全隔离:每个上下文拥有独立的Cookie、LocalStorage和会话状态
- 并行执行:多个上下文可以同时运行而不会相互干扰
- 设备模拟:每个上下文可配置不同的设备参数(如屏幕尺寸、UserAgent)
- 资源复用:共享底层浏览器进程,减少内存占用
实际测试中,我们经常遇到这样的场景:需要验证同一个网站在iPhone、iPad和桌面浏览器上的表现是否一致。传统方案需要启动三个独立的浏览器进程,而使用Playwright只需创建一个浏览器实例,然后派生三个上下文即可。
from playwright.sync_api import sync_playwright def run_test(): with sync_playwright() as p: # 创建浏览器实例(Chromium内核) browser = p.chromium.launch(headless=False) # 创建三个独立上下文 iphone_ctx = browser.new_context(**p.devices["iPhone 13"]) ipad_ctx = browser.new_context(**p.devices["iPad Pro 11"]) desktop_ctx = browser.new_context(viewport={"width": 1920, "height": 1080})2. 多设备并行测试实战
下面我们通过一个完整案例,演示如何利用单个Playwright实例同时测试三种设备:
import time from playwright.sync_api import sync_playwright def test_responsive_design(): with sync_playwright() as p: # 启动浏览器(建议开启headless模式以节省资源) browser = p.chromium.launch(headless=False) # 设备配置字典 devices = { "iPhone": p.devices["iPhone 13"], "iPad": p.devices["iPad Pro 11"], "Desktop": {"viewport": {"width": 1920, "height": 1080}} } # 为每个设备创建上下文和页面 contexts = {} for name, config in devices.items(): contexts[name] = { "context": browser.new_context(**config), "page": None } # 在所有设备上并行执行测试 start_time = time.time() for name, ctx in contexts.items(): page = ctx["context"].new_page() ctx["page"] = page # 导航到测试页面 page.goto("https://example.com") # 验证关键元素 expect(page.get_by_role("heading", name="Welcome")).to_be_visible() # 执行设备特定测试 if name == "iPhone": test_mobile_features(page) elif name == "Desktop": test_desktop_features(page) # 输出执行时间 print(f"Total execution time: {time.time() - start_time:.2f}s") # 清理资源 for ctx in contexts.values(): ctx["context"].close() browser.close() def test_mobile_features(page): # 测试移动端特有功能 page.get_by_label("Menu").click() expect(page.get_by_text("Mobile Menu")).to_be_visible() def test_desktop_features(page): # 测试桌面端特有功能 page.get_by_role("button", name="Expand Sidebar").hover() expect(page.locator(".sidebar")).to_have_class("expanded")关键配置参数对比
下表展示了三种设备的典型配置差异:
| 参数 | iPhone 13 | iPad Pro 11 | Desktop |
|---|---|---|---|
| 屏幕尺寸 | 390x844 | 834x1194 | 1920x1080 |
| 设备像素比 | 3.0 | 2.0 | 1.0 |
| UserAgent | 包含Mobile标识 | 包含Mobile标识 | 标准桌面UA |
| 触摸支持 | 启用 | 启用 | 禁用 |
| 地理位置 | 模拟特定坐标 | 模拟特定坐标 | 默认位置 |
3. 高级技巧与性能优化
3.1 资源共享与隔离策略
浏览器上下文提供了精细的资源控制能力:
# 创建带有特定存储状态的上下文 storage_state = { "cookies": [{"name": "session", "value": "abc123", "domain": "example.com"}], "origins": [] } context = browser.new_context( storage_state=storage_state, # 禁用图片加载加速测试 bypass_csp=True, java_script_enabled=False )3.2 网络条件模拟
每个上下文可以独立配置网络环境:
# 模拟3G网络 slow_3g = { "offline": False, "download_throughput": 500 * 1024, # 500KB/s "upload_throughput": 250 * 1024, # 250KB/s "latency": 200 # 200ms } context = browser.new_context( **p.devices["iPhone 13"], # 应用网络限制 network_conditions=slow_3g )3.3 并行执行模式
利用Python的concurrent.futures实现真正的并行测试:
from concurrent.futures import ThreadPoolExecutor def run_test_in_context(device_name, config): with sync_playwright() as p: browser = p.chromium.launch() context = browser.new_context(**config) page = context.new_page() # 执行测试逻辑... context.close() browser.close() devices = { "iPhone": p.devices["iPhone 13"], "iPad": p.devices["iPad Pro 11"], "Desktop": {"viewport": {"width": 1920, "height": 1080}} } with ThreadPoolExecutor(max_workers=3) as executor: futures = [ executor.submit(run_test_in_context, name, config) for name, config in devices.items() ] for future in concurrent.futures.as_completed(futures): future.result() # 获取执行结果或异常4. 常见问题解决方案
4.1 元素定位差异处理
不同设备可能需要不同的定位策略:
# 通用定位方法 def locate_element(page, desktop_selector, mobile_selector): if "Mobile" in page.context.device: return page.locator(mobile_selector) return page.locator(desktop_selector) # 使用示例 submit_button = locate_element( page, desktop_selector=".btn-submit", mobile_selector="//button[contains(@class, 'mobile-submit')]" ) submit_button.click()4.2 性能监控与优化
记录各上下文的性能指标:
# 启用性能监控 context = browser.new_context( record_har_path=f"har/{device_name}.har", record_video_dir="videos/" ) # 获取内存使用情况 metrics = page.evaluate(""" () => { return { jsHeapSizeLimit: window.performance.memory.jsHeapSizeLimit, usedJSHeapSize: window.performance.memory.usedJSHeapSize, totalJSHeapSize: window.performance.memory.totalJSHeapSize } } """)4.3 自动化测试最佳实践
- 测试数据隔离:为每个上下文使用独立的测试账号
- 失败重试机制:对网络不稳定的移动端测试增加重试逻辑
- 智能等待:结合Playwright的auto-wait和自定义等待条件
- 截图对比:保存各设备的渲染结果进行视觉回归测试
# 视觉回归测试示例 def test_visual_regression(page, device_name): page.goto("/product/page") page.locator(".product-image").screenshot(path=f"screenshots/{device_name}.png") # 使用第三方库进行图像对比 compare_images( f"screenshots/{device_name}.png", f"baseline/{device_name}.png", threshold=0.01 )浏览器上下文是Playwright区别于其他测试框架的核心特性,它让多设备、多场景的并行测试变得简单高效。通过合理配置上下文参数,我们可以用极少的资源完成过去需要多台设备才能实现的测试覆盖。
编程学习
技术分享
实战经验