跳转到内容

测试策略与 CI 实践

学习目标

  • 理解 Browser Use 的测试哲学:“禁止 mock,使用真实对象”
  • 掌握 pytest-httpserver 在浏览器测试中的应用
  • 了解 CI 流程和测试门禁

项目实践

测试哲学

Browser Use 有一条明确的测试规则(写入 CLAUDE.md):

Never mock anything in tests, always use real objects!! The only exception is the LLM.

为什么

  • 真实对象测试确保集成正确性
  • Mock 容易遗漏真实环境中的边界情况
  • LLM 是唯一例外:调用真实 LLM 成本高、不稳定、不可控

LLM Mock 模式

通过 pytest fixtures 设置 LLM 响应:

# conftest.py 中的 fixture
@pytest.fixture
def mock_llm():
"""返回模拟的 LLM,预设响应"""
return MockLLM(responses=[...])
# 测试中使用
async def test_agent_step(mock_llm):
agent = Agent(task="...", llm=mock_llm)
await agent.run()

pytest-httpserver 模拟网页

禁止使用真实远程 URL(如 https://google.com),必须用 pytest-httpserver 模拟:

@pytest.fixture
def test_server(httpserver):
"""设置本地测试服务器"""
html = """
<html>
<body>
<a href="/page2">Go to page 2</a>
<button id="submit">Submit</button>
</body>
</html>
"""
httpserver.expect_request("/").respond_with_data(html, content_type="text/html")
return httpserver
async def test_click_element(test_server):
url = test_server.url_for("/")
browser = BrowserSession()
await browser.navigate(url)
# ... 测试点击

每个测试独立设置 HTML

  • 为每个测试场景创建特定的 HTML 页面
  • 精确控制页面内容,避免外部依赖
  • 测试可重复、可离线运行

测试分类

通过 pytest markers 分类:

Marker说明运行方式
slow慢速测试(真实浏览器交互)-m 'not slow' 跳过
integration集成测试需要完整环境
unit单元测试快速运行
asyncio异步测试自动处理 event loop

CI 测试门禁

CI 测试路径tests/ci/

  • 所有通过的测试移入此目录
  • CI 自动发现并运行此目录下的所有测试
  • 特定场景的测试放在对应文件(如 tests/ci/test_action_ClickElement.py

运行命令

Terminal window
# CI 测试(快速子集)
uv run pytest -vxs tests/ci
# 所有测试
uv run pytest -vxs tests/
# 单个测试文件
uv run pytest -vxs tests/ci/test_specific_test.py

pytest 配置(pyproject.toml):

[tool.pytest.ini_options]
timeout = 300
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "session"
addopts = "-svx --strict-markers --tb=short --dist=loadscope"

并行测试:使用 pytest-xdist--dist=loadscope 模式,按测试文件并行而非按测试函数。

质量门禁

测试通过后移入 CI

开发流程:

  1. 新功能/修复在任意位置编写测试
  2. 测试通过后移入 tests/ci/
  3. 去重和压缩:将重复的测试逻辑合并到一个文件
  4. CI 自动运行

问题与规避

浏览器测试不稳定

问题:浏览器启动、渲染可能不稳定,导致 flaky tests。

对策

  • 300s 超时保护
  • 使用 pytest-httpserver 消除网络不稳定
  • LLM 使用 mock 消除模型不稳定
  • 特定场景用 pytest.mark.flaky 标记(如果有的话)

测试耗时过长

问题:浏览器测试每个操作都需要启动浏览器,耗时高。

对策

  • CI 只运行 tests/ci/ 快速子集
  • 慢速测试用 @pytest.mark.slow 标记,可选择性跳过
  • pytest-xdist 并行运行

设计取舍

全真实对象 vs 部分 Mock

方案优势代价
全真实对象(当前)集成正确性好测试耗时、依赖环境
部分 Mock测试快速可能遗漏集成问题

Browser Use 选择全真实对象(除 LLM 外),因为:

  • 浏览器交互的核心价值就是”端到端能工作”
  • 单元测试无法发现 CDP 协议变化、浏览器行为变化等问题
  • 代价是测试更慢,但 CI 通过 tests/ci/ 子集和并行来缓解

参考来源