ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Beads 测试指南:从 Bazel 门禁到测试设计的完整实践手册

Beads 测试指南:从 Bazel 门禁到测试设计的完整实践手册 AI 应用Agent 记忆CLIMCP 服务项目管理人工智能【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址https://gitcode.com/GitHub_Trending/beads1/beads点击查看免费下载本篇技术指南围绕 Beads 开源仓库engdocs/TESTING.md中「仓库级测试权威文档」展开它是 Beads 测试命令、测试选择与测试设计的唯一权威来源engdocs/README_TESTING.md明确将 Testing Guide 作为唯一入口。读完本文你将掌握 Beads 的 Bazel 测试门禁体系、全部 CI lane 的本地复现命令、go test内循环的用法与环境隔离机制、Dolt 测试服务器的两种后端以及如何按「最小有效测试」原则设计测试并在提交前正确跑完质量门禁。一、为什么 Bazel 是测试的门禁而非go testBeads 以 Bazel 作为构建与测试系统。CI 在.github/workflows/bazel.yml中对每个 Pull Request 执行bazel test车道并且有几类检查只以 Bazel 目标形式存在nogogo test自带的 vet 检查 golangci-lint 启用的 linter实现在 tools/nogo随每次 Go 编译并行运行gofmt//scripts/repochecks:fmt_test仓库守卫repository guards位于 scripts/repochecks 下的多个检查目标。因此一个普通的go test不会运行上述任何一项它只是内循环便利工具CI 并不强制执行。一项改动只有在对应的 Bazel lane 全部通过时才算就绪。在 Makefile 中make test正是 test lane 的命令bazel test //... --configci本地运行与 CI 共享相同的 action key 与远程缓存。二、安装 Bazelisk 与 Git Hooks安装 Bazelisk 并令其作为bazel命令它读取.bazelversion中钉定的 Bazel 版本。pre-commit hook对暂存包运行 nogo与 pre-push hook运行测试 lane都需要它。make install会将core.hooksPath指向.githooks从而启用pre-commit hook格式化暂存的 Go 文件并对其所在包运行 nogo等价于make lint-changed LINT_CHANGED_SCOPEstagedpre-push hook当推送的分支改动 Go 或 Bazel 输入时运行 scripts/pre-push-suite.sh即bazel test //... --configci并通过BD_PREPUSH_SUITE变量选择运行模式auto默认若 Bazel 的有效配置指名了远端执行器则用remote-exec否则用fork-cache未安装 Bazel 则退化为gorbe强制--configremote-exec无执行器配置则失败cache强制--configfork-cache匿名只读缓存go运行make test-go纯go test并以横幅明确提示这不是 CI 所门禁的套件。三、动作在哪里执行fork-cache、remote-exec 与 Agent Host「动作在哪里执行」由每台机器决定从不提交进仓库贡献者Contributors通过--configfork-cache读取 rbe-west 的匿名只读缓存——CI 已执行过的动作全部缓存命中未命中的在本地运行且不向远端上传任何结果。可在 gitignore 的.bazelrc.local中写入build --configfork-cache使其成为默认或按命令传递如make test BAZEL_FLAGS--configfork-cache。该配置在 .bazelrc 中定义指向grpcs://rbe-cache.ops.gascity.com:8443--noremote_upload_local_results并带--remote_local_fallback兜底。维护者Maintainers持有 rbe-west 客户端证书通过--configremote-exec远程执行执行器端点与 TLS 配置放在 gitignored 的user.bazelrc或.bazelrc.local中见.bazelrc中的注释。该配置只含通用调优--jobs64、--remote_download_minimal、--remote_timeout600等端点与凭据永不提交。Agent host若其~/.bazelrc已指名执行器则两个 flag 都无需显式添加。四、CI lane 全览命令即本地复现方式下表列出 bazel.yml 中的每条 lane非默认配置时请自行附加--configfork-cache或--configremote-execLanebazel.yml job命令说明Testbazel-testmake test即bazel test //... --configciPR Core 的选择race、-short、skip。包含 nogo、gofmt 与仓库守卫。每个 Go 改动的默认门禁。Lint全平台make ci-pr-lint原生 nogo windows/amd64 与 darwin/arm64 两个交叉 pass。make lint-changed只覆盖你改动的包。Pure-Gobazel-purebazel build --configpure //cmd/bd:bd //cmd/bd:bd_test关闭 cgo。job 的 cmd/bd 测试子集PURE_CMD_BD_TESTS、release 交叉编译与 js/wasm 步骤都在 bazel.yml 中。Integrationbazel-integrationbazel test //... --configintegrationintegration标签的构建。同样可使用只读缓存。Dolt serverbazel-doltserverbazel test //... --configdoltserver从钉定二进制启动自己的dolt sql-server无需 Docker。cmd/bd Dolt serverbazel-cmd-doltbazel test //cmd/bd:bd_dolt_server_test --configdoltserver-cmdintegration 标签 cmd/bd 套件的 16 个分片。Embedded Doltbazel-embeddedbazel test //... --configembedded仅 CI 远程执行本地很慢。Proxied serverbazel-proxiedbazel test //... --configdoltserver-proxied仅远程执行30 个分片每个带一个 Dolt server。Server-Dolt storagebazel-server-storagebazel test //... --configdoltserver-integration仅远程执行。Docsmake check-docs//test/docsync:docsync_test与//scripts/repochecks:doc_freshness_test以 test lane 配置运行随后以docs/cli-docs.pin钉定的 release 运行 scripts/check-doc-flags.sh。4.1 质量门禁组合与 Bazel 同步make check依次运行testing.Short策略检查、make ci-pr-lint与make test新增、删除、重命名 Go 文件或改动 import 与go.mod后必须运行make bazel-syncgazelle 重新生成 BUILD 文件、刷新go_srcsfilegroup 与MODULE.bazel对应校验目标为make bazel-sync-checkMakefile 为纯 Go 版本保留了显式-go命名的孪生目标make test-go对应 scripts/test.sh、make check-go、make check-docs-go。它们可离线、无需 Bazel 运行但不是 CI 强制执行的内容GitHub Actions 中仍在运行 Go 原生套件的 job 一律调用-go目标从不调用make test由TestWorkflowsNameTheirTestEngine测试约束。五、选择最小有效的测试Beads 的测试层级原则是在能因「用户可见原因」失败的、最低的接缝处测试。只有当下层无法证明某种独立风险时才上探更高层级例如集成接线、真实的持久化属性、进程边界或外部契约。这不意味着每个测试都必须是单元测试——当缺陷可能就在真实边界时就使用真实边界。需求命令何时使用纯文档改动校验git diff --check与make check-docs仅改散文时按改动路径补充生成文档或特定表面的链接检查。不要因为改了 Markdown 就跑全量套件。聚焦的红/绿循环bazel test //path/to/package:package_test --configci --test_filter^TestExactName$或纯 Go 的./scripts/test.sh -run ^TestExactName$ ./path/to/package/...编写或修复单个行为时。go test循环没问题但下面的 Bazel 目标才是门禁。受影响包信心bazel test //path/to/package/... --configci聚焦测试通过后当其契约变化时包含直接受影响的相邻包。最终门禁make test聚焦的 Go 改动变绿后运行一次整个测试 lane多为缓存命中。其它 lane 的风险上表中的对应命令改动触及该 lane 覆盖的内容时integration 标签文件、Dolt server 路径、embedded Dolt、pure-Go 构建。具名 CI 包装器make ci-pr-core或make ci-pr-lint运行风险或表面被影响的包装器或复现对应 CI 检查。不要为每次编辑例行跑全部三个。针对真实 timeout 实现的 hook shimbazel test //tests/hook_timeout_backends:hook_timeout_backends_test改动 cmd/bd/hooks.go 中的 hook 生成器随后make githooks-regen或.githooks/下内容后。将受跟踪的受管段落在 GNU coreutils、uutils、busybox、toybox 的timeout以及单独安装为gtimeout的多调用上运行覆盖有/无 Perl、dash/bash/busybox ash共 240 个用例约需一个 deadline 的墙钟时间无需 Go 构建。PR Core lane 在每个 PR 上都运行它。不要用重复的全量套件运行取代聚焦循环受影响测试变绿后跑一次make test即可。六、纯go test内循环scripts/test.sh 是make test-go背后的纯 Go 运行器它source.buildflagsCGO_ENABLED1GOFLAGS-tagsgms_pure_go见 .buildflags调用beads_test_env_enter创建隔离测试环境见下文读取并应用 .test-skip 中的跳过正则默认设置每包 25 分钟的 Go 测试超时——这是防挂死兜底不是目标运行时长仅当诊断合法慢路径时才覆盖它TEST_TIMEOUT30m ./scripts/test.sh ./cmd/bd/... TEST_VERBOSE1 ./scripts/test.sh ./cmd/bd/... TEST_RUN^TestExactName$ ./scripts/test.sh ./cmd/bd/... # 等价的命令行选项。 ./scripts/test.sh -v -run ^TestExactName$ ./cmd/bd/... ./scripts/test.sh -timeout 30m ./cmd/bd/...关于 25m 超时的来龙去脉脚本注释记录得很清楚cmd/bd是最慢的包其默认套件约 1490 个测试、约 1090 秒测试时间多数串行——subprocess 测试每次调用都启动 bd embedded Dolt且大多受t.Setenv约束无法t.Parallel()因此 3 分钟永远装不下25 分钟为该测量值加机群负载余量。脚本还会在测试前预构建一次 bd 二进制BEADS_TEST_BD_BINARY供 subprocess 风格测试使用避免十几个测试 helper 各自在测试内go build完整 bd——这是本地获得与 CI 相同的「预构建快速路径」的方式。仅当改动确实需要时才使用选入式 ICU 正则路径make test-icu-path它是维护者专用不属于常规校验。make test-full-cgo与./scripts/test-cgo.sh已降级为兼容别名。风险在范围内时才使用具名专项目标make test-regression make test-upgrade make test-cross-version make test-migration若某个 GitHub Actions 检查失败运行上表对应 bazel.yml lane 的命令对于非 Bazel lane 的 job跟随 workflow 及其 Makefile 目标。七、测试环境与就绪性beads_test_env_enter实现在 scripts/ci/lib/test-env.sh会隔离HOME、Git 配置与 Dolt 状态创建独立临时根目录设置私有HOME、XDG_CONFIG_HOME、DOLT_ROOT_PATH清空全局 gitconfigGIT_CONFIG_NOSYSTEM1unset 掉BEADS_DIR、BEADS_DB、BD_DB、BEADS_DOLT_PORT、BEADS_DOLT_SERVER_PORT等一揽子环境变量防止继承宿主状态默认将dolt加入BEADS_TEST_SKIP仅当你刻意要锻炼 Dolt 路径且其前置条件齐备时才设置BEADS_TEST_ENV_RUN_DOLT1。普通测试不得依赖开发者的数据库、守护进程、全局 Git 配置或文件系统状态。显式跳过可选服务BEADS_TEST_SKIPdolt ./scripts/test.sh ./...7.1 Dolt SQL Server 的两种后端需要 Dolt SQL server 的测试从internal/testutil获取EnsureDoltContainerForTestMain、RequireDoltContainer、StartIsolatedDoltContainer[Handle]、NewContainerProvider见 internal/testutil/testdoltserver.go。两个后端由BEADS_TEST_DOLT_SERVER选择container通过 testcontainers 启动dolthub/dolt-sql-server镜像需要 docker 与已拉取的镜像镜像 tag 由 internal/testutil/testdoltcommon.go 中的常量DoltDockerImage钉定。纯go test下的默认值。local由测试进程从钉定的 dolt CLIBEADS_TEST_DOLT_BINARY否则取PATH上的dolt且必须是镜像同版本启动dolt sql-server。无需 docker。仅在显式选择时使用go test与bazel test下皆可通过 Bazel 目标的env或--test_envBEADS_TEST_DOLT_SERVERlocal未设置即为container而在无 docker 的 Bazel 动作中会保持常规 skip。BEADS_TEST_REQUIRE_DOLT_CONTAINER1将后端不可用从 skip 变为失败每个测试及每个TestMain以运行 Dolt 套件为存在目的的 lane 都会设置它。BEADS_TEST_REQUIRE_SOCAT1对通过socat桥接外部端点的 proxied 子测试external-unix、断线/重连矩阵做同样的事//cmd/bd:bd_proxied_test设置它而无socat的遗留 GitHub proxied job 不设置。在 Bazel 下bazel test //... --configdoltserver以local后端运行 domain、uow、tracker、doctor/fix、protocol 与 testutil 套件dolt-server标签目标无需 docker--configremote-exec时在远端执行。没有 Bazel 目标使用container后端要锻炼它请在有 docker 与已拉取镜像的环境运行go test。7.2 共享服务器唯一的「自己起服务器」正道套件从不理会环境中残留的BEADS_DOLT_SERVER_PORT或BEADS_DOLT_PORTEnsureDoltContainerForTestMain成功时会用容器端口覆盖这两个变量任何原因无法启动包括BEADS_TEST_SKIPdolt时则清空两者因此没有任何环境指名服务器可被解析。要把测试指向特定 Dolt server请为它启动一个容器而不是导出端口。唯一受认可的手动共享服务器方式BEADS_TEST_SHARED_SERVER1 ./scripts/test.sh它启动一个dolt sql-server将其端口导出为BEADS_DOLT_PORT并以BEADS_TEST_SHARED_DOLT_SERVER标记该端口值即端口号见testdoltserver.go中的EnvSharedDoltServer常量。若到达时任一端口变量仍被设置则什么都不启动运行器已先清空两者仅当隔离被跳过——如BEADS_TEST_ENV_DISABLE1——才会发生。容器仍优先共享服务器是无 Docker 的路径。7.3 临时仓库、工作区隔离与手动 CLI 实验需要临时仓库或 store 的测试应使用t.TempDir()与t.Cleanup()临时仓库必须设置仓库级 hooks 路径不得继承开发者的全局 hooks 配置。在cmd/bd中fresh-workspace 命令 fixture 应在 setup/dispatch 前调用isolateBeadsDirForTest(t)定义于 cmd/bd/test_helpers_pure_test.go它清掉继承的BEADS_DIR并在 cleanup 时精确恢复该变量即使经过原始命令派生的修改。TestMain的 reset 只隔离启动。这些 fixture 不得使用t.Parallel()。有意选择 workspace 的测试应使用t.Setenv(BEADS_DIR, ...)initConfigForTest与ensureCleanGlobalState会保留该选择。手动 CLI 实验应在一次性工作目录中完成初始化和后续命令beads_manual_dir$(mktemp -d) ( set -e cd $beads_manual_dir bd init --quiet --prefix test --skip-hooks --skip-agents bd create Test issue -p 1 ) rm -rf -- $beads_manual_dirBEADS_DB只选择打开数据库的命令所用数据库本身不会重定向bd init的 workspace 设置。切勿仅因BEADS_DB指向别处就在生产 workspace 中手动运行bd init。Tmpfs 主机注意cmd/bd测试套件会创建隔离的$HOME与多个测试二进制位于$TMPDIR。正常由测试进程清理但 SIGKILL 或 OOM 的运行可能留下孤儿。在/tmp为 tmpfs 的主机如 Fedora Atomic / Bluefin上若du -sh /tmp/beads-* /tmp/bd-*显示累积请在测试运行之间执行make clean-test-tmp对应脚本 scripts/clean-test-tmp.sh。7.4testing.Short()策略testing.Short()只用于真正的运行时、压力或大型 fixture 跳过不能替代声明 integration/e2e/API/Docker/外部依赖边界。仓库通过 scripts/check-testing-short.sh 维护一个批准清单如internal/storage/dolt/concurrent_test.go::TestHighContentionStress、internal/testutil/fixtures/fixtures_test.go::TestXLargeDolt等新增使用必须落在仓库策略内make check-testing-short该脚本扫描所有.go文件中的testing.Short()调用将「文件::函数」键与允许清单比对未批准的用法直接报错退出。八、Dolt 容器测试与 podman-rootless 的两处已知坑任何未携带BEADS_TEST_SKIPdolt的测试包括BEADS_TEST_ENV_RUN_DOLT1与裸go test都会触达真实的dolt sql-server默认经 testcontainers-go有容器运行时与钉定镜像时否则这些套件自跳过或在使用testutil.RequireDoltBinary的套件中经本地doltCLI。设置BEADS_TEST_REQUIRE_DOLT_CONTAINER1的 lane 会失败而非跳过。识别下面两个容器化路径的局限避免把环境问题误读为产品 bug——两种失败模式都不会出现在生产或 GitHub Actions 上。坑一Migration 0032 在 wire 协议上挂起。Migration0032drop_schema_migrations_applied_at经容器化 sql-server 应用时无限挂起。go test ./internal/storage/uow/... -count1无BEADS_TEST_SKIP会传入context.Background()于是卡在initSchema直到包超时带 deadline 的调用者则会看到 server 模式 store 打开internal/storage/dolt/store.go的newServerMode报告failed to initialize schema: context deadline exceeded原因是 podman-rootless 容器端口转发路径而非 migration 0032 的 SQL相同语句经 embedded/CLI 引擎、以及匹配部署形态的裸宿主进程dolt sql-server都正常完成。除非你测试的正是容器路径否则使用BEADS_TEST_SKIPdolt。坑二关闭 Ryuk 会失去容器安全网。本仓库不设置TESTCONTAINERS_RYUK_DISABLEDCI 始终启用 Ryuktestcontainers-go 的孤儿收割 sidecar。podman-rootless 流程通常需手动关闭它TESTCONTAINERS_RYUK_DISABLEDtrue因为 rootless podman 下 Ryuk 常无法启动。Ryuk 关闭时测试进程未运行 cleanup 就退出如os.Exit先于 deferredTerminateDoltContainer所留下的容器无人收割。运行时应让 teardown 走在正常返回路径上testMainInner模式见根目录 beads_test.go事后检查孤儿。由于裸docker ps对话的是 CLI 默认端点、会误报一切正常请携带 rootless socket 并从钉定处读取镜像 tag而非手抄防止钉定移动后命令漂移dolt_image$(sed -n s/.*DoltDockerImage \(.*\).*/\1/p \ $(git rev-parse --show-toplevel)/internal/testutil/testdoltcommon.go) DOCKER_HOSTunix:///run/user/$(id -u)/podman/podman.sock \ docker ps -a --filter ancestor${dolt_image:?could not read the Dolt image pin}九、测试设计接缝、场景与替身9.1 语义一致性 vs 持久化一致性在能演示行为的最小接缝处为每个场景写一个测试覆盖改变用户结果的边界或失败模式示例共享 setup 时用表驱动子测试。不要仅仅因为「处处可用」就在 helper、每个调用者与 CLI 各重复一遍同一场景。录制式替身/假对象double/fake应当窄只建模测试所需的调用、输入、输出与失败不要为了「看起来真实」而重建存储引擎、进程管理器或其它子系统。行为式假对象不同若它代替多个生产实现共享的契约就应享有与这些实现相同的语义一致性套件。该共享套件定义可观察行为防止假对象教给调用者一个生产代码并不遵守的契约。语义一致性semantic conformance问的是同一操作下实现是否产出承诺的结果、错误与状态迁移。持久化一致性persistence conformance问的是真实持久化边界是否保持其必需的持久性、事务、迁移与恢复性质。两者回答不同的问题。除非既有契约及其一致性套件已确立否则不要宣称后端对等。9.2 层级准入Tier Admission集成测试只有覆盖窄替身无法证明的独立边界时才应置于单元接缝之上例如配置接线、真实文件系统或 Git 交互、子进程协议、持久化行为。端到端测试仅在以下全部成立时准入失败对用户可见真实进程、setup 或接线边界拥有较低接缝无法证明的独立失败风险低层测试在切实可行处覆盖底层行为让端到端测试聚焦于该边界没有已有端到端测试覆盖同一边界风险。低层对同一用户旅程的覆盖并不取消端到端测试资格对同一边界风险的重复覆盖才取消。请在测试名或邻近文档中声明该风险。9.3 避免偶然复杂性除非下列模式正是被测行为否则应避免在多层重复同一场景全局状态重置编舞——优先每测试状态与清理为单元级断言启动子进程、监听器、sleep 或真实 store契约是可观察行为时断言私有实现形态没有可重复测量与声明工作负载的性能断言。当测试恰好关于计时、生命周期、协议或持久化时sleep、监听器与真实 store 是恰当的请把 setup 保持在作用域内并让理由显而易见。十、失败、跳过与提交前检查.test-skip是本地、临时的例外清单当前仓库版本为空清单仅含注释模板。若无关失败已在清单中上报它而非默默扩大跳过新增 skip 前记录其追踪的 issue底层失败修复后移除该 skip。提交 PR 前纯文档改动运行适用的 docs、link、freshness 与 diff 检查默认不跑全量套件。Go 代码保持聚焦与受影响包测试绿色然后运行一次最终make testBazel test lane外加改动触及的其它层级对应 lane。只运行改动表面所需的具名 CI 包装器、专项目标或风险门禁或复现某个 CI 结果所需的那一个。历史 CI 清单与维护者规划背景可参考 CI_TEST_SURFACE_AUDIT.md 与 CI_CLEANUP_PLAN.md当前命令一律以 workflow 文件与Makefile为准这些背景文档不是第二份测试指南也不是实时 CI 清单。小结Beads 的测试体系以「Bazel 为门禁、go test为内循环」为骨架所有 lane 命令都能本地复现并共享 CI 的 action key 与远程缓存环境隔离保证测试不依赖开发者机器状态internal/testutil提供容器与本地两种 Dolt 后端配合BEADS_TEST_SKIP/BEADS_TEST_REQUIRE_DOLT_CONTAINER等开关精确控制就绪性测试设计则强调最小接缝、语义/持久化一致性区分与端到端准入四条件。遵循本文的 lane 表与提交前检查清单即可让改动在本地获得与 CI 一致的验证结果。赞分享AI 应用Agent 记忆CLIMCP 服务项目管理人工智能【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址https://gitcode.com/GitHub_Trending/beads1/beads点击查看免费下载相关推荐Beads 项目测试指南从最小缝测试到 CI 验证的完整实践手册Beads 项目测试指南从最小缝测试到 CI 验证的完整实践手册 导读 本文以 Beads 仓库的 engdocs/TESTING.md https://lAI 应用Agent 记忆CLIMCP 服务项目管理人工智能QtScrcpy手机投屏到电脑键鼠映射手游按键3步搞定QtScrcpy手机投屏到电脑键鼠映射手游按键3步搞定 和平精英决赛圈敌人趴在三十米外的房区里你左手拇指拖着摇杆、右手食指拖着视角手心一紧就拉过头。桌面应用音视频如何快速部署Neural Collaborative Filtering完整Docker实战教程如何快速部署Neural Collaborative Filtering完整Docker实战教程 Neural Collaborative Filtering上一篇CrackingTheSQLInterview高级篇视图、存储过程与触发器的企业级应用下一篇Ivy Wallet安全机制解析如何保护你的财务数据隐私创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进