
Browser Use Demo 测试套件实战指南从 pytest 配置、Mock 策略到边缘用例全覆盖【免费下载链接】claude-quickstartsA collection of projects designed to help developers quickly get started with building deployable applications using the Claude API项目地址: https://gitcode.com/GitHub_Trending/an/claude-quickstarts本指南以 browser-use-demo/tests/README.md 为核心骨架深入剖析 Browser Use Demo基于 Claude Playwright 的浏览器自动化参考实现重构后的测试体系如何安装依赖、运行单测与覆盖率报告、按 marker 筛选用例以及MessageRenderer、Streamlit 辅助函数和端到端集成测试分别覆盖了哪些行为。结合仓库中的 pytest.ini、conftest.py 与各测试文件源码你将掌握一套面向 Streamlit 异步事件循环 浏览器工具的三层 Mock 测试方法论并能够直接复用到自己的 Agent 应用中。测试套件概览这套测试套件服务于重构后的 Browser Use Demo入口与架构见 browser-use-demo/README.md。它的设计目标有两个无需真实浏览器即可测试通过 Mock 掉 Streamlit 组件、BrowserTool避免引入 Playwright 依赖和 asyncio 事件循环使测试可以在纯 Python 环境快速执行边缘用例全覆盖针对消息渲染、会话状态初始化、事件循环管理等高风险逻辑构造空值、类型错误、状态不一致、并发修改、超长输入等异常输入验证系统的健壮性。从测试文件规模看详见测试结构一节test_message_renderer.py约 300 个用例、test_streamlit_helpers.py约 150 个用例、test_integration.py约 50 个用例共同构成了对该 demo 消息展示层与 Streamlit 交互层的高密度回归保障。安装测试依赖有两种等价方式安装测试依赖# 方式一直接安装 test-requirements.txt pip install -r test-requirements.txt # 方式二通过 setup.py 的 extras 安装推荐与 CI 一致 pip install -e .[test]两种方式引入的依赖完全一致见 test-requirements.txt 与 setup.py 中extras_require[test]的定义依赖版本用途pytest8.3.3测试框架核心pytest-cov4.1.0覆盖率统计--covpytest-mock3.11.1基于monkeypatch的 Mock 工具pytest-asyncio0.23.6asyncio 测试支持对应asynciomarker需要说明的是pip install -e .[test]同时会安装 setup.py 中的运行时依赖streamlit、anthropic、playwright、boto3、google-auth 等。由于本项目要求 Python 版本 3.11python_requires3.11请确保解释器版本满足要求。运行测试运行全部测试pytest tests/pytest.ini中的testpaths tests已经限定了测试目录因此直接执行pytest也能达到同样效果。带覆盖率报告运行pytest tests/ --covbrowser_tools_api_demo --cov-reporthtml # 打开 htmlcov/index.html 查看覆盖率报告--covbrowser_tools_api_demo指定统计目标为被测包。关于这个包名需要留意文章撰写时 pytest.ini 与tests/README.md中仍写的是重构前的旧包名browser_tools_api_demo而当前源码中实际被测模块位于 browser_use_demo/ 下例如 message_renderer.py因此若要统计真实覆盖率应使用pytest tests/ --covbrowser_use_demo --cov-reporthtml这一点属于仓库演进过程中的文档滞后请以当前源码为准。运行指定测试文件pytest tests/test_message_renderer.py -v-v输出每个用例的详细结果。pytest.ini的addopts中已经默认附加了-v所以即使不加也能看到详细输出。运行指定测试类或测试方法# 运行整个测试类 pytest tests/test_message_renderer.py::TestMessageRenderer -v # 运行单个测试方法用 :: 逐级定位 pytest tests/test_message_renderer.py::TestRenderMethod::test_render_string_message -v按 marker 筛选测试pytest.ini中声明了三个自定义 markermarkers integration: Integration tests that test multiple components slow: Tests that take longer than usual to run asyncio: Tests that use asyncio对应的筛选命令# 只运行集成测试 pytest -m integration # 排除集成测试只跑单元测试 pytest -m not integration # 运行 asyncio 相关测试 pytest -m asyncio注意addopts中带有--strict-markers意味着未在pytest.ini注册的 marker 会直接报错这也是项目要求测试分类必须显式声明的原因。此外pytest.ini还做了如下全局配置python_files test_*.py/python_classes Test*/python_functions test_*限定测试发现规则asyncio_mode auto所有async def测试自动以 asyncio 模式运行无需逐个标注asyncio_default_fixture_loop_scope functionasyncio fixture 的 loop 作用域默认为函数级--tbshort、--disable-warnings控制失败回溯与警告输出minversion 3.11强制最低 Python 版本filterwarnings忽略DeprecationWarning与PendingDeprecationWarning避免第三方库弃用警告干扰输出。测试结构browser-use-demo/tests/ ├── conftest.py # Shared fixtures and mocks ├── test_message_renderer.py # MessageRenderer class tests (~300 test cases) ├── test_streamlit_helpers.py # Helper function tests (~150 test cases) └── test_integration.py # End-to-end integration tests (~50 test cases)各文件职责如下文件被测对象侧重点conftest.py无测试基建共享 fixture、Mock 环境、路径注入test_message_renderer.pyMessageRenderermessage_renderer.py消息渲染的输入分支与异常处理test_streamlit_helpers.pysetup_state/get_or_create_event_loop/authenticatestreamlit.py会话状态、事件循环、鉴权逻辑test_integration.py渲染管线 状态 事件循环组合跨组件端到端行为conftest.py通过sys.path.insert(0, str(Path(__file__).parent.parent))将被测包根目录注入sys.path使测试可以from browser_use_demo.tools import ToolResult直接导入。测试覆盖详解MessageRenderertest_message_renderer.pyMessageRenderer 是 Streamlit 聊天界面的消息渲染器其核心职责是把三种来源用户输入、assistant 回复、工具结果统一渲染为界面组件。Sender类定义了三种发送者USER user、BOT assistant、TOOL tool。测试覆盖的行为包括初始化以各种状态配置创建MessageRenderer包括Nonesession state、空 state对应TestMessageRenderer的三个用例渲染所有消息类型字符串消息、字典消息text/tool_use/ 未知type、ToolResult对象。例如test_render_dict_message_tool_use_type验证tool_use消息会被格式化为Tool Use: name\nInput: input并交给st.code展示会话历史渲染render_conversation_history对多消息、未知 role、缺失 content 字段、Nonecontent、列表 content、嵌套结构、tool_result关联等场景的处理。其中test_skip_image_blocks_in_history验证历史渲染会跳过 image 块避免重复展示截图而test_tool_result_in_assistant_message验证tool_result会从session_state.tools中按tool_use_id查找对应的ToolResult并渲染边缘用例空消息跳过渲染、None消息跳过渲染、循环引用不死循环、畸形ToolResult优雅降级、渲染异常按预期传播、Base64 解码失败等Unicode 与特殊字符如Hello 世界 \n\t\r ñáéíóú可被完整渲染对应test_render_unicode_special_chars大消息性能10 万字符长消息可正常渲染test_render_very_long_message。值得注意的细节test_render_tool_result_with_hidden_screenshots验证了session_state.hide_screenshots开关——开启时只渲染文本、不调用st.image这是聊天界面中隐藏截图功能的直接回归保障。Streamlit Helperstest_streamlit_helpers.py该文件针对 streamlit.py 中的三个关键函数setup_state()初始化st.session_state。测试覆盖全新初始化所有默认键被写入、部分初始化已存在的键不覆盖、环境变量缺失、lambda 惰性求值model依据 provider 动态确定、BrowserTool初始化失败时异常传播、状态损坏时异常传播、并发调用setup_state的线程安全5 个线程并发无崩溃、只读状态下的AttributeErrorget_or_create_event_loop()管理 asyncio 事件循环。测试覆盖无 loop 时新建、已有 closed loop 时重建、已有 open loop 时复用、创建/设置 loop 失败时的异常传播、存在 running loop 时仍新建独立 loop 等场景authenticate()鉴权。测试覆盖有效 key 通过、缺失/Nonekey 时调用st.error并st.stop、非 Anthropic provider如 BEDROCK在空 key 情况下也放行。集成测试 test_integration.py 中的TestCompleteStateInitialization还给出了setup_state初始化键的完整清单messages、api_key、provider、model、max_tokens、system_prompt、hide_screenshots、tools、browser_tool、event_loop、rendered_message_count、is_agent_running、active_messages、active_response_container可作为理解该函数行为的权威参考。集成测试test_integration.py所有集成测试类都标注了pytest.mark.integration因此可用pytest -m integration单独执行。覆盖范围完整消息渲染管线TestFullMessageRenderingPipeline构造包含用户文本、assistanttool_use、tool_result分别指向成功与失败的ToolResult的混合会话验证st.markdown/st.write/st.error的调用次数符合预期状态初始化与持久化TestStateInitializationAndPersistence验证全新状态初始化出全部必需键且多次渲染间状态保持一致事件循环与异步操作TestEventLoopManagementWithAsync验证 loop 的创建/复用、异步 Agent 执行与asyncio.gather并发任务处理错误传播TestErrorPropagationAndHandling验证缺失工具的tool_result被优雅处理不调用st.error、初始化失败后二次调用可恢复side_effect依次抛异常/成功完整用户交互工作流TestCompleteWorkflow从setup_state→ 用户输入 → 事件循环 →run_agent全链路模拟性能与可扩展性TestPerformanceAndScalability验证 1000 条消息的历史渲染断言st.markdown恰好被调用 1000 次以及 100 层嵌套内容不栈溢出。覆盖的边界用例1. 边界条件空字符串、空列表、空字典单元素集合最大尺寸输入10 万字符单条消息、100 万字符 content 块见conftest.py中edge_case_messages[huge_message]Null/None值消息 content 为None、key 为None。2. 类型不匹配期望字段类型错误如role为整数123缺少必填字段{role: user}无 content、{content: No role}无 role多余意外字段非法消息结构malformed_dict。3. 状态不一致引用了session_state.tools中不存在的tool_use_idmissing_toolfixture 专门构造此场景部分初始化的状态渲染过程中的并发修改test_concurrent_modification在渲染期间清空 tools损坏的状态访问即抛异常。4. 错误条件导入错误asyncio 异常新建/设置 loop 失败环境变量错误clean_environment删除ANTHROPIC_API_KEYLambda 求值失败Base64 解码错误test_base64_decode_error中 patchbase64.b64decode抛出异常。5. 性能边界1000 条消息的历史记录100 层深层嵌套test_deeply_nested_content/test_deeply_nested_content_performance均构造 100 层 wrapper循环引用_create_circular_reference让 content 列表包含自身Unicode 与特殊字符。Mock 策略Streamlit 组件所有 Streamlit 组件被整体 Mock使测试无需运行真实的 Streamlit 服务器即可验证渲染行为。Mock 清单与文档一致且在conftest.py的mock_streamlitfixture 中可以看到具体实现方式使用patch(streamlit.session_state)初始化默认状态hide_screenshotsFalse、tools{}、messages[]、api_keytest-key等再用嵌套的with patch(...)依次 Mockst.chat_message、st.markdown、st.write、st.error、st.code、st.image并通过字典把全部 mock 对象返回给测试用例使用。特别要注意st.chat_message是上下文管理器with st.chat_message(...)形式因此 fixture 中为mock_chat.return_value显式设置了__enter__/__exit__。外部依赖BrowserTool通过mock_browser_toolfixture 整体 Mock避免引入 Playwright 浏览器依赖。注意当前重构后的版本BrowserTool()已不再从环境变量读取尺寸参数conftest.py中相关注释和test_streamlit_helpers.py中被移除的测试均印证了这一点asyncio 事件循环mock_asyncio_loop使用Mock(specasyncio.AbstractEventLoop)构造受控 looprun_until_complete直接委托给asyncio.run环境变量mock_environment/clean_environment基于 pytest 的monkeypatch设置或删除ANTHROPIC_API_KEY从而无副作用地测试环境变量存在/缺失两种场景。Fixtures 一览conftest.py提供的共享 fixtures 及其职责Fixture职责mock_streamlit完整的 Streamlit 组件 Mock 集含默认 session_statemock_browser_toolBrowserTool的 MagicMock 实例sample_tool_result5 种ToolResult形态成功、错误、含截图真实 1x1 PNG 的 Base64、空、全字段sample_messages覆盖普通 / 复杂 / 边缘 / Unicode / 超长 / 嵌套结构的消息样本edge_case_messages专门触发边界与错误的输入空列表、None、畸形字典、循环引用、缺失工具、非法类型、100 万字符巨块mock_asyncio_loop受控 asyncio 事件循环mock_environment设置测试环境变量clean_environment删除环境变量模拟缺失场景mock_provider模拟APIProvider枚举anthropic / bedrock / vertexmock_api_response_with_text_and_tools模拟同时含文本与多个tool_use的 API 响应mock_tool_collection模拟ToolCollection含tool_map与to_paramssample_mixed_content_messages文本与工具调用混合的完整对话流sample_tool_result中真实 PNG 的 Base64iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ...保证了带截图渲染路径能够走完实际的 Base64 解码逻辑。持续集成CI实践将测试接入 CI 的标准流程与tests/README.md一致# 1. 安装依赖 pip install -e .[test] # 2. 运行测试并输出 XML 与终端覆盖率 pytest tests/ --covbrowser_tools_api_demo --cov-reportxml --cov-reportterm # 3. 生成覆盖率徽章 coverage-badge -o coverage.svg与前文同理--cov的目标包名建议按当前源码改为browser_use_demo。coverage-badge需要单独安装pip install coverage-badge它读取上一步生成的覆盖率数据产出 SVG 徽章用于在仓库 README 中展示。贡献测试代码的规范tests/README.md对新增功能与重构提出了明确的测试要求这也是本项目持续保持高测试密度的机制保障新增功能必须配套相应测试确保所有边缘用例被覆盖提交前运行完整测试套件维持 95% 的代码覆盖率若测试结构发生变化同步更新本 README。配套的静态检查依赖ruff、pyright、pre-commit定义在 setup.py 的devextras 中可作为 CI 流水线的质量关卡。关键要点回顾三种运行粒度全量pytest tests/、按文件/类/方法::定位、按 marker-m integration/-m not integration/-m asyncio自由组合两层 Mock 体系Streamlit 组件层mock_streamlit与外部依赖层BrowserTool、asyncio、环境变量让测试完全不依赖真实浏览器与网络覆盖率统计结合pytest-cov输出 HTML/XML/终端报告但需注意仓库文档中旧包名browser_tools_api_demo与当前源码browser_use_demo的差异高密度边界覆盖从 100 万字符消息、100 层嵌套、循环引用到并发修改、Base64 解码失败测试套件系统地验证了渲染层与状态层的健壮性可复用价值conftest.py的 fixture 设计尤其是 Streamlit 上下文管理器 Mock 与事件循环 Mock可直接迁移到其他基于 Streamlit Anthropic SDK 的 Agent 项目中。如需深入底层实现建议对照阅读 message_renderer.py渲染逻辑、streamlit.pysetup_state/authenticate/ 事件循环以及 pytest.ini测试发现与 marker 配置三者与测试文件互为印证能帮助你完整理解这套测试体系的每个断言背后的真实行为。【免费下载链接】claude-quickstartsA collection of projects designed to help developers quickly get started with building deployable applications using the Claude API项目地址: https://gitcode.com/GitHub_Trending/an/claude-quickstarts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考