Pydoll测试自动化集成:与pytest无缝对接教程
你还在为浏览器自动化测试配置繁琐的WebDriver而烦恼吗?Pydoll作为一款无需WebDriver即可控制Chromium浏览器的Python库,结合pytest的测试框架,能让你轻松实现高效的Web测试自动化。本文将详细介绍如何将Pydoll与pytest无缝集成,从环境搭建到编写复杂测试用例,让你快速掌握这一强大组合。读完本文,你将能够:
- 快速搭建Pydoll与pytest的测试环境
- 编写异步的浏览器测试用例
- 利用Pydoll的事件系统捕获网络请求
- 实现页面交互、截图和PDF导出等测试场景
- 掌握测试用例的组织和最佳实践
环境准备与安装
Pydoll基于Python 3.10+开发,使用poetry进行依赖管理。根据pyproject.toml文件显示,项目已内置pytest及相关插件支持,包括pytest-asyncio用于异步测试,pytest-cov用于覆盖率分析。
安装步骤
- 克隆项目仓库:
git clone https://gitcode.com/GitHub_Trending/py/pydoll
cd pydoll
- 使用poetry安装依赖:
poetry install
- 验证安装是否成功:
poetry run pytest --version
核心依赖说明
根据pyproject.toml文件,测试相关的核心依赖包括:
| 依赖包 | 版本 | 用途 |
|---|---|---|
| pytest | ^8.3.3 | 核心测试框架 |
| pytest-asyncio | ^0.24.0 | 支持异步测试用例 |
| pytest-cov | ^6.0.0 | 生成测试覆盖率报告 |
| aioresponses | ^0.7.7 | 模拟异步HTTP请求 |
Mermaid流程图展示测试环境架构:
基础测试用例编写
Pydoll与pytest的集成主要通过异步测试用例实现。项目测试目录tests/下的文件展示了多种测试场景,例如tests/test_browser_page.py中包含了页面操作的完整测试示例。
第一个测试用例:页面初始化
import pytest
from pydoll.browser.page import Page
@pytest.mark.asyncio
async def test_page_initialization():
# 创建Page实例,连接到本地Chromium浏览器
page = Page(connection_port=9223, page_id='test_page')
# 验证页面初始状态
assert not page.page_events_enabled
assert not page.network_events_enabled
assert not page.fetch_events_enabled
assert not page.dom_events_enabled
使用pytest fixtures优化测试代码
为避免重复创建测试对象,可使用pytest fixtures功能。参考tests/test_browser_page.py中的实现:
import pytest_asyncio
from unittest.mock import patch
@pytest_asyncio.fixture
async def mock_connection_handler():
with patch('pydoll.browser.page.ConnectionHandler', autospec=True) as mock:
handler = mock.return_value
handler.execute_command = AsyncMock()
handler.register_callback = AsyncMock()
handler.network_logs = []
yield handler
@pytest_asyncio.fixture
async def page(mock_connection_handler):
page = Page(connection_port=9223, page_id='test_page')
page._connection_handler = mock_connection_handler
return page
使用fixture后的测试用例更加简洁:
@pytest.mark.asyncio
async def test_current_url(page):
# 模拟返回结果
page._connection_handler.execute_command.return_value = {
'result': {'result': {'value': 'https://example.com'}}
}
# 调用Pydoll的API
url = await page.current_url
# 断言结果
assert url == 'https://example.com'
page._connection_handler.execute_command.assert_called_once()
高级测试场景实现
页面导航与加载等待
Pydoll提供了go_to方法实现页面导航,并内置页面加载等待机制。测试用例示例:
@pytest.mark.asyncio
async def test_go_to_success(page):
# 模拟页面加载完成
page._wait_page_load = AsyncMock(return_value=None)
page._connection_handler.execute_command.return_value = {
'result': {'result': {'value': 'https://another.com'}}
}
# 导航到测试页面
await page.go_to('https://example.com')
# 验证导航命令是否正确执行
page._connection_handler.execute_command.assert_called_with(
PageCommands.go_to('https://example.com'), timeout=60
)
网络请求监控
Pydoll支持捕获网络请求,可用于验证前端API调用是否正确。测试实现:
@pytest.mark.asyncio
async def test_get_network_logs(page):
# 模拟网络日志
page._connection_handler.network_logs = [
{'params': {'request': {'url': 'https://example.com/api'}}},
{'params': {'request': {'url': 'https://example.com/other'}}},
]
# 过滤包含'api'的请求
logs = await page.get_network_logs(['api'])
# 验证结果
assert len(logs) == 1
assert logs[0]['params']['request']['url'] == 'https://example.com/api'
# 测试不存在的请求
with pytest.raises(LookupError):
await page.get_network_logs(['nonexistent'])
截图与PDF导出测试
Pydoll支持网页截图和PDF导出功能,测试用例示例:
@pytest.mark.asyncio
async def test_get_screenshot(page, tmp_path):
# 模拟图片数据
test_image = b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/wcAAgAB/edzE+oAAAAASUVORK5CYII='
page._connection_handler.execute_command.return_value = {
'result': {'data': test_image.decode()}
}
# 保存截图
screenshot_path = tmp_path / 'screenshot.png'
with patch('aiofiles.open') as mock_open:
mock_open.return_value.__aenter__.return_value.write = AsyncMock()
await page.get_screenshot(str(screenshot_path))
# 验证命令调用
page._connection_handler.execute_command.assert_called_once_with(
PageCommands.screenshot(), timeout=60
)
测试用例组织最佳实践
目录结构
推荐的测试目录结构如下:
tests/
├── test_browser_commands.py # 浏览器命令测试
├── test_browser_page.py # 页面操作测试
├── test_network_commands.py # 网络相关测试
├── test_dom_commands.py # DOM操作测试
└── test_input_commands.py # 用户输入测试
参数化测试
使用pytest的参数化功能,减少重复代码:
import pytest
@pytest.mark.parametrize("url,expected", [
("https://example.com", "Example Domain"),
("https://github.com", "GitHub"),
])
@pytest.mark.asyncio
async def test_page_titles(page, url, expected):
page._connection_handler.execute_command.return_value = {
'result': {'result': {'value': expected}}
}
await page.go_to(url)
title = await page.execute_script("return document.title")
assert title == expected
测试报告生成
项目pyproject.toml中配置了测试命令:
[tool.taskipy.tasks]
test = 'pytest -s -x --cov=pydoll -vv'
post_test = 'coverage html'
执行测试并生成HTML报告:
poetry run task test
报告将生成在htmlcov目录下,打开index.html即可查看详细的测试覆盖率信息。
常见问题与解决方案
异步测试超时
当测试涉及网络请求或页面加载时,可能需要增加超时时间:
@pytest.mark.asyncio
async def test_long_running_operation(page):
# 设置较长的超时时间
await page.go_to('https://example.com', timeout=120)
浏览器实例管理
对于多个测试用例共享浏览器实例的场景,可使用session级别的fixture:
@pytest_asyncio.fixture(scope="session")
async def browser_session():
browser = await Browser.launch()
yield browser
await browser.close()
事件监听冲突
当多个测试用例需要启用不同事件监听时,应在teardown阶段清理:
@pytest.mark.asyncio
async def test_event_listening(page):
try:
await page.enable_network_events()
# 执行测试操作
finally:
await page.disable_network_events()
总结与展望
通过本文的介绍,你已经了解如何将Pydoll与pytest无缝集成,实现高效的Web测试自动化。Pydoll的无WebDriver设计和异步特性,结合pytest的灵活测试框架,为现代Web应用测试提供了强大支持。项目的测试代码tests/目录中包含了更多详细示例,建议进一步研究学习。
未来,Pydoll计划增强更多高级测试功能,包括视频录制、性能分析和跨浏览器支持。如果你在使用过程中遇到问题或有功能需求,欢迎参与项目贡献。
Mermaid流程图展示Pydoll测试工作流:
掌握Pydoll与pytest的集成,将显著提升你的Web测试效率和质量。立即开始尝试,体验无WebDriver的浏览器自动化测试新方式!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



