ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Visdom 测试体系实战指南:pytest 单元测试与 Playwright E2E/视觉回归的完整实践

Visdom 测试体系实战指南:pytest 单元测试与 Playwright E2E/视觉回归的完整实践 数据可视化前端【免费下载链接】visdomTool for real-time visualization, monitoring and collaborative analysis of AI/ML experiments and live data. Supports Python, PyTorch/Torch, NumPy, TensorFlow/Keras https://visdom.dev项目地址https://gitcode.com/gh_mirrors/vi/visdom点击查看免费下载导读Visdom 是面向 AI/ML 实验的实时可视化与监控工具其前后端分别由 PythonTornado 服务端 客户端 SDK与 React前端面板构成。为了保证从纯逻辑函数到浏览器渲染层的每一环都可验证仓库建立了一套双层测试体系pytest负责 Python 单元/集成测试纯函数、服务端工具、窗口与环境生命周期Playwright负责 E2E 功能测试与视觉回归同时辅以演示脚本做人工/视觉校验。读完本文你将掌握 Visdom 测试套件的完整运行命令、目录组织约定、fixture 与 marker 的用法、CI 门禁设计以及如何正确地为 Visdom 编写新的测试这一核心实战能力。一、双层测试架构总览Visdom 的测试体系刻意保持两层、各司其职的划分依据 .agents/context/testing.md层工具覆盖范围判定方式Python 测试层pytest纯函数、服务端工具、窗口/环境生命周期、HTTP 路由断言可自动判定E2E/视觉层Playwright浏览器内的功能流程连接、面板 CRUD、文本/图片/属性渲染与像素级视觉回归断言 截图比对人工校验层演示脚本全类型窗口的人类视角渲染检查肉眼观察关键设计原则是凡是能自动化判定的都放进 pytest 或 Playwright需要人工观察 UI 的放进example/manual/。例如 example/manual/visual_check.py 会在visual_check环境下依次绘制折线、散点、直方图、图片、文本等所有类型的窗口供开发者打开浏览器人工核对——它需要真实运行中的服务端因此永远不被 pytest 收集。二、运行 Python 测试pytest2.1 最小可用命令集按 .agents/context/testing.md 给出的完整命令pip install -r test-requirements.txt # 包含 pytest、pytest-cov pytest # 运行 py/tests/ 下被追踪的整套用例 pytest -m not server # 跳过需要真实服务的用例CI 默认 pytest -m unit # 快速迭代循环约 2 秒 pytest -m not server --covvisdom --cov-reportterm-missing # CI 门禁所用命令几个容易被忽略的细节-q已经写进了pyproject.toml的addopts -ra -q再传一个-q会变成-qq反而隐藏了 pass/fail 汇总需要可用的--collect-only统计数时应追加-o addopts覆盖掉默认 addopts可选测试依赖tensorflow、xgboost在 test-requirements.txt 中声明unit/keras_logger.py与unit/test_xgboost_logger.py共 39 个用例依赖它们未安装时收集总数会减少。2.2 pytest 配置解读pyproject.toml全部配置集中在 pyproject.toml 的[tool.pytest.ini_options]段配置项值作用testpaths[py/tests]将发现范围锁定在py/tests/仓库根目录下的实验性test_*.py及test/目录天然不被收集pythonpath[py, py/tests]让import visdom与import testutils无需 editable 安装即可解析python_files[*.py]unit/、integration/下的.py文件全部按测试模块收集因此文件名不必重复test_前缀norecursedirsvisdom、testutils、__pycache__等testutils/保持可导入但不可收集visdom包本身被排除避免pytest .时导入可选依赖导致崩溃addopts-ra -q简洁输出 汇总markersserver、unit、integration、slow注册四个自定义标记这里有一个值得注意的工程决策py/tests/目录故意不放置__init__.py——因为 setup.py 通过find_packages(wherepy)打包若py/tests成为包会把顶层的tests发行包误发给用户而testutils/自身是包凭借pythonpath中的py/tests可达。2.3 测试目录结构与命名约定py/tests/ conftest.py # 共享 fixturespytest 自动加载 testutils/ # 可导入的辅助实现fakes、payload 构造、HTTP 基类 unit/ # 纯逻辑无 Application、无 tmp_path 之外的 I/O integration/ # 进程内 Application、真实 HTTP 或 handler 分发命名约定文件名按覆盖内容命名如integration/window_types.py而非integration/test_window_types.py——unit/与integration/目录本身已表明这是测试文件名不再重复但测试函数与Test*类仍保留常规前缀python_classes [Test*]、python_functions [test_*]。2.4 共享 fixturespy/tests/conftest.pypy/tests/conftest.py 定义了整套测试共享的 fixtures全部遵循hermetic封闭原则只用临时目录不监听任何端口、不访问网络Fixture提供内容env_path一次性环境目录基于tmp_pathstore/spy_storeJSONStore/ 记录后端调用次数的SpyStoreapp/app_factory挂在临时env_path上的Application端口仅记录、不绑定可并行构造工厂用于重载断言handler/app_handler鸭子类型 handler独立空状态或共享某个Application的状态/存储/订阅者fake_socket记录write_message的假 socket提供.commands()与.last(cmd)断言方法offline_clientVisdom(sendFalse)的替代品——永不打开连接的客户端capture_send执行一次客户端调用返回本应发送的 payloadinline_executor把IOLoop.current().run_in_executor调用改为线程内立即执行并记录调度让磁盘写入在调用返回时即已落定其中reset_warn_once是autousefixtureshared_utils.warn_once依赖模块级集合去重若不重置前一个测试触发的警告会静默抑制后一个测试中相同的警告导致断言结果随执行顺序漂移。它通过保存/恢复shared_utils._seen_warnings实现隔离见 py/visdom/utils/shared_utils.py 与 conftest 第 198-209 行。offline_client的实现值得深入它在构造Visdom(use_incoming_socketFalse)时用patch.object拦截_handle_post与_start_session_reaper构造后再把_handle_post替换为会抛AssertionError的 Mock——这样任何绕过测试自身 patch 的调用都会响亮地失败而非静默触网配合capture_send即可对 payload 做断言。三、编写 Python 测试风格取决于是否需要 HTTP3.1 两种测试风格的取舍核心决策点测试是否需要真实的 HTTP 往返。测试需求写法原因不需要Application或只需 handler 对象普通def test_*()函数fixtures 与parametrize都能用需要真实 HTTP 往返继承VisdomHTTPTestCasetornado.testing.AsyncHTTPTestCase本身是unittest.TestCase由它负责启动应用pytest 无法向TestCase方法注入 fixtures——def test_x(self, app)会直接失败只有 autouse fixtures 能到达它们pytest.mark.parametrize对TestCase同样无效替代做法是写一个小型_assert_*helper由多个单行测试方法调用。但模块级pytestmark pytest.mark.integration对TestCase类是生效的所以每个文件都必须设置它。3.2 HTTP 测试基类testutils.VisdomHTTPTestCaseAsyncHTTPTestCase已在进程内、自己的IOLoop上运行Application每个请求经io_loop.run_sync驱动。文档明确告诫不要用后台线程、手写 asyncio 循环或进程外服务替换它——这些方案不带来任何收益且曾被尝试过又回退了TestCase风格是使用它的既定代价。py/tests/testutils/http.py 在基类之上提供了完整助手post_json、create_window、create_text_window、update、close_window、win_exists、get_win_data对应/win_data端点、get_envs、save、panes直接从self._app.state取存活 pane 字典。每个测试都有独立env_path在tearDown中按先停 socket 监控 → 停 autosave → 关闭 storage executor → 清理临时目录的顺序释放资源防止定时器与存储线程泄漏到下一个测试。通过app_kwargs类属性即可改变服务端配置例如只读模式的测试class TestReadonlyRoutes(VisdomHTTPTestCase): app_kwargs {readonly: True}由于 fixtures 无法触达TestCase共享资源放在类上self.env_path存临时目录多个测试类共用的助手抽一个介于VisdomHTTPTestCase与具体测试类之间的中间基类参见 py/tests/integration/window_types.py 中的WindowTypeTestCase。需要同一目录上的第二个Application做重载断言时直接Application(port8097, env_pathself.env_path)构造即可——此处没有app_factory。3.3 测试替身testutils/fakes.pypy/tests/testutils/fakes.py 提供三个关键替身FakeSocket第 24 行模拟订阅者/来源 socketwrite_message全部记录.sent解码 JSON.commands()按序返回所有command值.last(cmd)返回最近一条匹配消息FakeHandler第 64 行鸭子类型 handler镜像ServerState经StateAccessorsMixin暴露的字段使同一对象既能驱动 web handler 的 wrap 函数也能驱动 socket 的on_message分发write/set_status捕获响应体与状态码SpyStore第 146 行继承真实JSONStore并统计每次后端调用list_envs、load_env、save_env、delete_env、save_undo等同时记录调用线程名——用于证明服务端通过DataStore抽象触达持久化、且磁盘工作确实交给了 storage executor 而非 IOLoop。3.4 Markers 与套件完备性不变量四个 marker 均在 pyproject.toml 注册Marker含义是否进入 CI 默认运行unit无Application、除tmp_path外无 I/O是也是快速门禁任务integration进程内Application、真实 HTTP 或 handler 分发是slow耗时数秒以上是本地可选择性跳过server需要外部启动的 visdom 真实端口否规则是每个文件顶部都设置pytestmark pytest.mark.unit或pytest.mark.integration对普通函数与TestCase类同样适用——这不是装饰因为 CI 以-m unit作为门禁任务未标记的文件在两个任务中都不被覆盖实际上只靠较慢的那次运行兜底。由此形成的不变量是-m unit与-m integration之和必须等于整套套件。可用收集数验证pytest py/tests --collect-only -q -o addopts | tail -1 # 2369 pytest -m unit --collect-only -q -o addopts | tail -1 # 1597 pytest -m integration --collect-only -q -o addopts | tail -1 # 772如果数字对不上说明某个文件丢了 marker。目前被追踪的套件中没有任何server标记的用例——py/tests/下一切皆 hermetic 是设计使然需要真实服务的脚本应放在 example/manual/对应脚本 example/manual/visual_check.py。3.5 保持套件快速10 秒内的工程约束整套测试在十秒以内跑完这是需要主动维护的指标。破坏它的最常见原因是客户端未使用use_incoming_socketFalse构造——这样的客户端会等待 socket 连接超时每个测试白白耗费 6.3 秒integration/experiment_log_handler.py曾因此让 43 秒的总耗时中 38 秒被浪费。正确做法优先使用offline_clientfixture而非手工构造Visdom若必须手工构造传use_incoming_socketFalse并 patch_handle_post它是客户端唯一的 I/O 点注意sendFalse构造参数已不存在用pytest --durations10揪出耗时大户。四、E2E 与视觉回归测试Playwright4.1 运行命令npx playwright install chromium # 首次安装浏览器 npm test # WebSocket 功能测试 npm run test:polling # Polling 功能测试 npm run test:gui # 交互式 UI 模式--ui npm run test:init # 生成基线截图 npm run test:visual # 视觉截图比对前置条件确保端口8098可用。Playwright 配置会自动拉起一个隔离的 Visdom 服务。4.2 配置解读playwright.config.jsplaywright.config.js 是 WebSocket 通道的主配置testDir: ./playwright/tests测试发现范围锁定在playwright/tests/webServer自动执行visdom -port 8098 -env_path /tmp并等待http://localhost:8098就绪CI 下不复用已有服务、超时 120 秒baseURL: http://localhost:8098testIgnore排除*.init.spec.js与screenshots.spec.js它们由独立的 init/visual 配置运行metadata.transport: websocket标记传输通道polling变体见 playwright.polling.config.js基线/比对配置见 playwright.init.config.js 与 playwright.visual.config.js。4.3 测试文件清单与编写规范功能规格文件全部位于 playwright/tests/文件覆盖内容basic.spec.js连接页面加载、online/offline 指示器、手动重连pane.spec.js面板 CRUDtext.spec.js文本窗口image.spec.js图片窗口properties.spec.js属性窗口modal.spec.js模态框misc.spec.js杂项功能screenshots.init.spec.js基线截图生成screenshots.spec.js截图比对编写规范依据 .agents/context/testing.md新 spec 放在playwright/tests/参考 basic.spec.js、pane.spec.js、text.spec.js的模式如basic.spec.js中test.describe(Test Setup)beforeEach(page.goto(/)) 对textonline可见性的断言共享的浏览器与 demo 辅助代码放在 playwright/support/如 helpers.js 中负责定位 Python 可执行文件、管理子进程的辅助函数先跑test:init生成基线再跑test:visual比对——视觉回归正是拿 PR 截图与基线分支截图做对比。五、CI 流水线与覆盖率策略5.1 双任务门禁python-tests.yml.github/workflows/python-tests.yml 在每个 PR以及 push 到 master/dev上运行两个任务unit门禁任务Python 3.12 上执行pytest -m unit几秒内完成。它 gating 后面的矩阵任务——明显的破坏会在三次 torch 安装开始之前就失败从而节省 CI 资源pytest矩阵任务needs: unit在 3.12/3.13 矩阵上执行pytest -m not server --covvisdom --cov-reportterm-missing。5.2 覆盖率报告而非强制当前总覆盖率约84%但没有--cov-fail-under阈值——设定阈值需要整个代码库都能承受的数字这是独立的决策报告存在的意义就是让这个数字基于真实数据而非猜测被选定设定下限时必须考虑两点py/visdom/loggers/sklearn.py108 条语句与 py/visdom/pytorch.py39 条按设计保持 0%——autolog()会 monkey-patch 每一个 sklearn estimator 且没有 un-patch API测试它会污染整个会话。要么在[tool.coverage.run]中排除它们要么设定一个容忍其缺失的下限--cov参数放在 workflow 而非pyproject.toml的addopts中——若放进 addopts每次本地pytest都会硬性要求 pytest-cov并拖慢单文件运行。5.3 其他相关流水线视觉回归PR 截图与基线分支截图比对.github/workflows/update-js-build-files.ymlmaster 上自动重新编译 JS.github/workflows/pypi.ymlVERSION 变化时发布到 PyPI。六、回归检查与调试手册6.1 人工回归检查在改动分支与干净分支上分别运行python example/demo.py肉眼确认渲染无差异——这是浏览器层回归的最终兜底手段。6.2 调试工具箱手段用途visdom -logging_level DEBUG打开详细日志visdom -env_path /tmp使用干净状态启动不污染真实环境/win_data端点直接查看窗口的原始 JSON 数据对应get_win_data测试助手npm run dev启动 webpack watch提供 source maps 便于前端调试浏览器 DevTools → Network → WS 标签检查 WebSocket 消息流检查py/visdom/static/蓝屏前端资源缺失时核对 CDN 文件是否齐全generatedlint 错误直接丢弃对py/visdom/static/的改动该目录是生成产物见 .github/workflows/update-js-build-files.yml七、边界与原则总结Hermetic 是硬约束py/tests/下不允许外部启动的服务、不允许浏览器、不允许需要人工判定的断言需要真实服务或肉眼判断的脚本一律进example/manual/像素正确性是 Playwright 的职责不是 pytest 的——pytest 管逻辑与协议Playwright 管渲染marker 是纪律每个文件顶部的pytestmark直接决定该文件是否进入 CI 门禁unitintegration必须等于整套套件速度需要主动守护use_incoming_socketFalse是单元测试构造客户端的唯一正确姿势pytest --durations10是例行体检工具覆盖率为决策服务报告存在的意义是让未来的--cov-fail-under阈值有真实数据支撑而不是为了装饰。这套pytest 管逻辑、Playwright 管渲染、人工脚本管兜底的分层体系加上 10 秒级套件与 CI 双门禁为 Visdom 这种实时可视化 前后端联动的项目提供了可复制、可持续的测试工程范式。核心配置与实现均可直接查阅 pyproject.toml、py/tests/conftest.py、py/tests/testutils/ 与 playwright.config.js。赞分享数据可视化前端【免费下载链接】visdomTool for real-time visualization, monitoring and collaborative analysis of AI/ML experiments and live data. Supports Python, PyTorch/Torch, NumPy, TensorFlow/Keras https://visdom.dev项目地址https://gitcode.com/gh_mirrors/vi/visdom点击查看免费下载相关推荐PostHog 桌面应用测试体系解析单元测试、Playwright E2E 与 Storybook 视觉回归的完整实践PostHog 桌面应用测试体系解析单元测试、Playwright E2E 与 Storybook 视觉回归的完整实践 PostHog 桌面应用 produ数据分析后端前端数据可视化大数据如何快速部署BloodyADActive Directory渗透测试完整教程如何快速部署BloodyADActive Directory渗透测试完整教程 BloodyAD是一款功能强大的Active Directory权限提升框架专VexFlow测试与调试完整单元测试和视觉回归测试实践VexFlow测试与调试完整单元测试和视觉回归测试实践 VexFlow是一个功能强大的JavaScript音乐符号渲染库它提供了一套完整的测试框架来确保代码上一篇iOS开发进阶SkeletonView实现复杂动画序列下一篇RedisInsight战略转型从命令行工具到数据资产治理平台的技术范式演进创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表