Meteor 自测框架(Self-Test)完全指南:端到端测试的运行、编写与内部原理

发布时间:2026/9/20 9:21:27
Meteor 自测框架(Self-Test)完全指南:端到端测试的运行、编写与内部原理 后端前端开发工具移动开发【免费下载链接】meteorMeteor, the JavaScript App Platform项目地址https://gitcode.com/gh_mirrors/me/meteor点击查看免费下载Meteor 的 Self-Test自测是运行在真实meteor命令之上的端到端测试体系它通过./meteor self-test启动用一套独立的Sandbox/Run抽象在隔离环境中创建应用、执行 CLI 命令并断言输出。本文以 tools/tool-testing/README.md 为主线结合 selftest.js、sandbox.js、run.js 等实现源码完整讲解如何运行、筛选、编写自测用例并剖析其背后的超时控制、标签过滤、测试状态记录等机制帮助你为 Meteor 工具链写出可维护的端到端测试。什么是 Self-TestSelf-Test 是 Meteor 工具meteor-tool自身的端到端测试框架它不 mock 内部模块而是直接以子进程方式启动真实的meteor可执行文件模拟用户在终端中的完整操作流创建应用、修改文件、运行命令、观察输出、验证退出码。所有测试用例存放在 tools/tests/ 目录下每个.js文件通过调用selftest.define()注册若干用例。运行 Self-Test 有一个硬性前提只能在 checkout 源码目录下运行。在 tools/cli/commands.js 中可以看到明确校验if (! files.inCheckout()) { Console.error(self-test is only supported running from a checkout); return 1; }因此你需要先通过 git 拉取 Meteor 源码仓库再在仓库根目录执行自测命令。快速开始运行 Self-Test在仓库根目录执行./meteor self-test regexpregexp是一个可选的 JavaScript 正则表达式用于按用例名称过滤测试。例如只运行名称中包含mongo的用例./meteor self-test mongo若不传正则则运行全部可用用例。命令本身在 tools/cli/commands.js 中注册hidden: true属隐藏命令最多接受 1 个位置参数。慢机器上的时间缩放TIMEOUT_SCALE_FACTOR自测中大量操作等待应用启动、等待输出匹配都有超时限制。在慢速机器上可以通过环境变量把所有超时统一放大# Unix / macOSbash/zsh export TIMEOUT_SCALE_FACTOR3 # Windowscmd set TIMEOUT_SCALE_FACTOR3其底层实现在 tools/utils/utils.jsvar timeoutScaleFactor 1.0; if (process.env.TIMEOUT_SCALE_FACTOR) { timeoutScaleFactor parseFloat(process.env.TIMEOUT_SCALE_FACTOR); }而 run.js 中每次匹配的超时计算为let timeout this.baseTimeout this.extraTime; // baseTimeout 默认 20 秒 timeout * timeoutScaleFactor; // 乘以缩放因子即默认基础超时为 20 秒waitSecs(n)累加的额外时间与之相加后整体乘以TIMEOUT_SCALE_FACTOR。设置为3意味着所有超时放大三倍适合 CI 或性能较弱的开发机。预览--preview执行前先用--preview查看筛选后哪些用例会运行、哪些会被跳过而不真正执行./meteor self-test --preview从 selftest.js 的实现看预览模式会对每个用例打印will run或will skip随后直接进入下一个用例。分批执行--skip 与 --limit--skip number和--limit number用于把测试分批跑完。它们的语义是在正则过滤之后再做跳过/限制而不是二次过滤# 第一批前 50 个 ./meteor self-test --limit 50 # 第二批跳过前 50 个再取 50 个 ./meteor self-test --skip 50 --limit 50对应逻辑在 selftest.js 的shouldSkipCurrentTestif (limit skip) { return currentTestIndex skip || (currentTestIndex - skip) limit; } if (limit) { return currentTestIndex limit; } if (skip) { return currentTestIndex skip; }注意--skip/--limit作用于已经过正则、标签等过滤后的最终列表所以分批时各批之间的用例集合不会因为过滤规则而错位适合在本地分片跑大批量用例。完整命令行选项self-test命令在 tools/cli/commands.js 中注册了以下选项选项类型默认值作用regexp位置参数—按用例名称正则过滤--changedBooleanfalse只运行自上次通过后发生过变更的文件中的用例--force-onlineBooleanfalse跳过离线检测强制运行net标签用例--slowBooleanfalse包含slow标签的用例--galaxyBooleanfalse只运行 galaxy 相关的用例--browserstackBooleanfalse使用 Browserstack 客户端--phantomBooleanfalse使用 PhantomJS 客户端--headlessBooleanfalse无头模式关闭进度条等可视化输出--history nNumber100失败时打印的最后输出行数--listBooleanfalse只列出用例不执行--file regexpString—按测试文件名正则过滤--exclude regexpString—按用例名称正则排除--with-tag tagString—只运行带指定标签的用例--without-tag tagString—跳过带指定标签的用例--junit pathString—输出 JUnit XML 报告到指定路径--retries nNumber2失败用例的最大重试次数--skip nNumber—过滤后跳过前 n 个用例--limit nNumber—过滤后最多运行 n 个用例--previewBooleanfalse只展示运行计划不执行离线自动检测除非显式传入--force-online框架启动时会尝试请求http://www.google.com/探测网络若判定离线则自动跳过带net标签的用例见 tools/cli/commands.js。因此在没有外网的环境如飞机上、内网 CI中默认行为是自动排除需要联网的用例。编写第一个自测用例注册机制所有测试存放在 tools/tests/ 目录。框架启动时selftest.js会遍历该目录下所有以.js结尾的文件require它们文件内的selftest.define()调用即完成注册export function define(name, tagsList, f) { if (typeof tagsList function) { // tagsList 是可选参数可以省略 f tagsList; tagsList []; } const tags tagsList.slice(); tags.sort(); allTests.push(new Test({ name, tags, file: fileBeingLoaded, fileHash: fileBeingLoadedHash, func: f, })); }每个用例包含name用例名、tags排序后的标签数组、file所在文件名、fileHash文件内容的 SHA-1用于--changed变更追踪、func测试函数体。另外selftest.js 还提供了selftest.skip.define(name, tags, f)用于注册一个默认被跳过的用例会被自动打上manually-ignored标签适合暂时禁用某些失败用例。内置断言自测框架在 selftest.js 中提供了一组轻量断言API作用fail(reason)直接抛出TestFailure使用例失败expectEqual(actual, expected)使用 EJSON 深度比较两个值是否相等expectTrue(actual)断言值为真值expectFalse(actual)断言值为假值expectThrows(f)断言调用f()会抛出异常这些断言都会通过parseStackMarkTop修饰保证失败时打印的调用栈从测试代码开始而不是从断言实现内部开始。完整示例MongoDB failover 测试README 中给出的典型示例其现代版本实现在 tools/tests/mongo.jsvar selftest require(../tool-testing/selftest.js); var Sandbox selftest.Sandbox; // 验证 observeChanges 在 MongoDB failover 后仍然正常工作 selftest.define(mongo failover, [slow], async function () { var s new Sandbox(); await s.init(); s.set(METEOR_TEST_MULTIPLE_MONGOD_REPLSET, t); await s.createApp(failover-test, failover-test); s.cd(failover-test); var run s.run(--once, --raw-logs); run.waitSecs(120); await run.match(SUCCESS\n); await run.expectEnd(); await run.expectExit(0); });这段代码完整演示了自测的四个核心步骤创建 Sandboxnew Sandbox()建立完全隔离的测试环境独立目录、独立 HOME、独立会话文件设置环境s.set()注入自定义环境变量此处启用多 mongod 副本集准备应用s.createApp()从模板拷贝应用s.cd()切换工作目录驱动 meteor 命令s.run(--once, --raw-logs)启动真实 meteor 进程run.match()匹配 stdout、run.expectEnd()断言输出结束、run.expectExit(0)断言退出码为 0。waitSecs(120)为下一步操作额外增加 120 秒超时MongoDB failover 场景耗时较长。注意示例中的await框架支持异步测试函数s.init()等初始化必须await。测试模板应用模板位于 tools/tests/apps/如empty、failover-test、standard-app、app-config等包模板位于 tools/tests/packages/。createApp(to, template)会从模板目录cp_r拷贝整个应用自动忽略local目录并确保应用不触发额外 upgrader模板中的~package-name~占位符会被createPackage()替换为真实包名见 sandbox.js。Sandbox隔离的测试环境Sandbox是自测的核心抽象代表一个独立的 meteor 工具安装。创建 Sandbox 会生成一个临时目录files.mkdtemp()内部再建home目录作为该沙箱的 HOME所有运行都指向沙箱内的 meteor 脚本与用户真实环境、其他沙箱互不干扰sandbox.js。注意new Sandbox()若需要构建包来准备环境构建失败时会抛出TestFailure因此只能在测试函数内部调用。Sandbox 常用方法方法说明run(...args)启动一次 meteor 运行返回Run对象createApp(to, template, options?)从 tools/tests/apps 模板拷贝应用到沙箱createPackage(dir, name, template)从 tools/tests/packages 模板创建包cd(relPath, callback?)切换后续运行的 cwd传回调时执行后自动还原set(name, value)/unset(name)设置/清除后续运行的环境变量write(filename, contents)写文件相对于沙箱 cwdutf8append(filename, contents)追加文件read(filename)/readDir(dir)读文件/目录不存在返回nullcp(from, to)在沙箱内复制文件常用于切换 package.js 备份内容mkdir/unlink/rename目录与文件操作readSessionFile()/writeSessionFile(contents)读取/覆盖.meteorsession可保存与恢复登录态沙箱自动注入的环境变量每次run()都会通过_makeEnv()sandbox.js注入关键环境变量METEOR_SESSION_FILE指向沙箱内独立的.meteorsession登录态不污染真实用户METEOR_WAREHOUSE_DIR、METEOR_OFFLINE_CATALOGt、SANDBOXtrue当使用模拟 warehouse 时设置METEOR_TEST_LATEST_RELEASE无模拟 warehouse 时把当前 release 伪装成最新版TOOL_NODE_FLAGS继承SELF_TEST_TOOL_NODE_FLAGS用于给被测试应用配置 Node 参数。此外 run.js 在构造Run时还会注入SELFTESTt和METEOR_NO_WORDWRAPt标识自测进程并关闭输出折行。模拟 warehouse 与 fakeMongonew Sandbox({ warehouse: {...} })可构造模拟发布仓库传入形如{ version1: { tool: tools1 }, version2: { recommended: true, tool: tools2, upgraders: [a] } }的配置框架会从 checkout 构建出对应的模拟 release 集合仅支持 checkout 模式用于测试版本切换、upgrader 等逻辑sandbox.js。new Sandbox({ fakeMongo: true })会让应用启动 tools/tests/fake-mongod 中的 mongod 桩进程之后可通过Run.tellMongo()向桩发送控制命令详见下文用于模拟 MongoDB 崩溃、failover 等故障场景。Run驱动 meteor 子进程Run对象代表一次对 meteor 可执行文件的测试运行通过Sandbox.run(...args)创建。其构造函数run.js支持args命令行参数、cwd、env、client浏览器客户端、fakeMongo等选项并默认设置 20 秒基础超时。输出匹配match 系列match(pattern)等待 stdout 中出现匹配文本正则或字符串并消费到该位置为止的输出超时或进程先退出而未匹配则用例失败。相关方法方法说明match(pattern)在 stdout 中向前搜索匹配matchErr(pattern)在 stderr 中向前搜索匹配read(pattern)类似 match但不允许跳过——必须紧跟上次匹配/读取的位置readErr(pattern)read 的 stderr 版本matchBeforeExit(pattern)匹配一次性模式不敏感于顺序进程结束前完成匹配即可matchErrBeforeExit(pattern)同上针对 stderrgetMatcherFullBuffer()获取到目前为止的完整输出缓冲匹配由 matcher.js 中的Matcher异步实现输出以流方式写入缓冲区并尝试匹配超时产生match-timeout失败进程退出仍有未消费输出则产生junk-before失败。退出断言expectExit / expectEndawait run.expectExit(0); // 断言进程以退出码 0 结束可省略参数仅等待退出 await run.expectEnd(); // 断言退出且 stdout/stderr 均无多余输出expectEnd()在expectExit()基础上进一步要求两个输出流都被完全消费干净防止测试漏掉意外输出。若实际退出码与期望不符会抛出wrong-exit-code失败并同时打印期望值与实际值含 signal。禁止模式forbid 系列run.forbid(regexp); // 整个运行过程中 stdout 不得出现该模式 run.forbidErr(regexp); // stderr 不得出现 run.forbidAll(regexp); // 两个流都不得出现⚠️重要陷阱README 明确提示forbid()检查的是从运行开始到当前的全部输出而不是从调用点之后的输出——因为输出是异步流式匹配的。所以forbid应当在进程结束后如expectExit之后调用才能覆盖完整输出。其他控制方法waitSecs(secs)为下一次操作match/expectExit 等增加额外超时秒数write(string)向进程 stdin 写入内容模拟交互输入stop()杀掉进程并等待退出内部_killProcess()在 Windows 上使用taskkill /f /t以连子进程一起终止connectClient()若 Run 带客户端创建连接浏览器客户端用于客户端测试。失败原因一览run.js 的runTest会对失败进行分类打印常见TestFailure原因包括失败原因含义spawn-failure进程未能成功启动exit-timeout进程超时未退出wrong-exit-code退出码与期望不符match-timeout匹配超时no-match进程结束时仍未匹配到模式junk-before匹配后存在未消费的输出not-equal/not-true/not-false断言失败expected-exception期望抛异常但未抛出mongo-not-running无法连接到 fake-mongod 桩失败时默认打印最后 100 行输出可用--history n调整并自动过滤掉tools/tool-testing内部栈帧直接定位到tools/tests/xxx.js:行号。Tags 标签分类、过滤与跳过标签是自测的元数据机制注册时传入的任意字符串数组都会被排序后存入用例。标签本身只是数据要让标签产生过滤效果需要修改 selftest.js 中的筛选逻辑——README 对此有明确说明。框架内置了以下标签语义见 selftest.js 的tagDescriptions与注册注释标签语义slow测试很耗时只有传--slow才运行windows仅在 Windows 上运行net需要访问外部网络服务离线时自动跳过checkout只能在 checkout 源码目录下运行galaxyGalaxy 平台集成测试--galaxy时启用且隐含slownetcordova需要 Cordova 支持Windows 上自动跳过custom-warehouse需要自定义模拟 warehousemanually-ignored通过selftest.skip.define注册默认排除筛选逻辑在getFilteredTests()selftest.js中执行先按正则、文件、变更状态等附加伪标签non-matching、in other files、unchanged、excluded、non-galaxy再按平台自动跳过windows非 Windows或cordova/yet-unsolved-windows-failureWindows。命令行可通过--with-tag/--without-tag进一步精确控制。浏览器客户端测试testWithAllClients对于需要真实浏览器环境的应用Sandbox 提供testWithAllClients(f, options)方法为每个已启用的客户端各创建一个Run并执行回调f(run)sandbox.jsawait s.testWithAllClients(async function (run) { run.connectClient(); // 连接浏览器客户端 await run.match(some text); // 匹配应用页面输出 }, { testName: my client test, testFile: client-tests, args: [--once], });客户端默认指向应用的localhost:3000可通过clients.port修改。支持的客户端类型Puppeteer默认总是启用见 tools/cli/commands.jsPhantom传--phantom启用BrowserStack传--browserstack启用且需满足其前置条件SDK 凭据等不满足时自动忽略。客户端的timeout会被设为对应Run的baseTimeout保证页面加载等待与整体超时机制一致。高级能力变更追踪、重试与 JUnit 报告--changed只跑变更过的用例框架会把每个测试文件的 SHA-1 哈希与通过状态记录在~/.meteortest版本 1 的 JSON字段lastPassedHashes。传--changed时若某文件当前哈希与上次全部通过时的哈希一致则该文件用例被标记为unchanged并跳过selftest.js。这非常适合日常开发先全量跑一遍建立基线之后只验证改动过的文件。--retries失败自动重试--retries n默认值为2。单个用例失败时runTest会在重试次数耗尽前重新执行整个用例函数run.js对偶发性的时序问题如端口竞争有很好的容错。注意每次重试都会重新执行用例完整流程因此用例本身必须可重复执行。--junitCI 集成传--junit path会生成标准的 JUnit XML 报告每个测试文件对应一个testsuite每个用例对应一个testcase失败时嵌入error/failure元素及失败详情selftest.js可直接接入 Jenkins、GitLab CI 等平台的测试报告解析。常见陷阱GotchasSelf-Test 的文档就是代码本身README 明确指出 The docs for self-test is reading the code of self-test——框架没有独立的规范文档所有行为细节以 selftest.js 源码为准阅读源码是最可靠的参考。forbid()是全局匹配它约束整个运行的输出而非调用点之后的输出异步流式匹配所致。应在expectExit/expectEnd之后调用。必须在 checkout 中运行./meteor self-test会直接拒绝在已发布版本环境执行。Sandbox 只能在测试函数内创建准备环境需要构建包失败会抛TestFailure不要在测试外复用。read()不跳读与match()不同read()严格要求模式紧跟上次消费位置否则会得到junk-before失败。标签需要改代码才生效新增标签语义必须修改 selftest.js 的筛选逻辑。测试资产速览路径内容tools/tests/全部自测用例文件每个.js文件用selftest.define注册tools/tests/apps/应用模板empty、failover-test、standard-app等tools/tests/packages/包模板~package-name~占位符替换tools/tests/fake-mongod/mongod 桩进程配合fakeMongotellMongo使用tools/tool-testing/selftest.js框架核心注册、筛选、断言、报告tools/tool-testing/sandbox.jsSandbox 隔离环境实现tools/tool-testing/run.jsRun 子进程驱动与超时控制tools/cli/commands.jsself-testCLI 命令注册与全部选项掌握了 Self-Test 的运行命令、Sandbox/Run 双抽象和标签过滤机制后你就可以为任何 meteor-tool 行为编写端到端用例并在本地、CI 中按需分片、重试、输出 JUnit 报告让工具链的质量验证完全自动化。赞分享后端前端开发工具移动开发【免费下载链接】meteorMeteor, the JavaScript App Platform项目地址https://gitcode.com/gh_mirrors/me/meteor点击查看免费下载相关推荐Nuxt 测试指南用 nuxt/test-utils 编写 Nuxt 运行时单元测试与端到端测试Nuxt 测试指南用 nuxt/test utils 编写 Nuxt 运行时单元测试与端到端测试 本篇基于 Nuxt 官方文档 Testing https:前端后端Web框架SSRKnative Serving测试框架如何编写和运行端到端测试Knative Serving测试框架如何编写和运行端到端测试 Knative Serving作为基于Kubernetes的Serverless应用平台其测云原生后端微服务Milvus 集成测试框架实战指南基于 MiniClusterV3 的端到端测试编写与运行Milvus 集成测试框架实战指南基于 MiniClusterV3 的端到端测试编写与运行 本文基于 Milvus 仓库的 tests/integration数据库向量数据库分布式数据库后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考