Resume-Matcher 测试策略与验证方案:从「绿勾即剧院」到 444 个确定性测试与本地 pre-push 门禁
【免费下载链接】Resume-MatcherThe #1 AI Harness for Building Resumes, PDFs, Cover Letters & more, locally with 100+ LLMs support.项目地址: https://gitcode.com/GitHub_Trending/re/Resume-Matcher
本文基于仓库内 docs/agent/testing-strategy.md(Status: Living document,2026-05-30 起稿于
test/backend-coverage-foundation分支,base 为dev)展开。该文档记录了 Resume-Matcher 后端(apps/backend,Phase 1–6)与前端(apps/frontend,vitest,§8)的一次系统化测试审计与整改计划,其门禁是本地pre-push钩子而非 PR CI。文章将以原文档为骨架,结合 apps/backend/pyproject.toml、.githooks/pre-push、apps/backend/tests/ 下各测试模块源码,完整还原这一「从评估到落地」的测试治理实践,并给出可直接复制的运行命令、覆盖缺口地图与阶段路线图。
Resume-Matcher 是一个本地运行、支持 100+ LLM 的简历/PDF/求职信 AI 工具箱。本文的核心主题是:当「构建在合并后才被发现坏了」「用户反馈 Ollama 不工作、简历渲染不出来」,而现有测试套件却从未被任何自动化执行时,如何用证据驱动的方式重构测试策略。读完本文,你将掌握:如何用覆盖矩阵定位「真实覆盖 vs 缺失覆盖」、如何区分确定性测试与 LLM Eval 并让两者各司其职、如何用respx在 HTTP 传输层复现「Ollama 不工作」类回归、以及如何用.githooks/pre-push本地钩子代替 PR CI 守住dev/main的绿。
1. TL;DR:这篇文档在说什么
原文档用五句话点明了全部结论,先整体复述:
- 仓库已经存在一套真实的后端测试套件:192 个测试,基于
pytest+pytest-asyncio+httpx。不需要换框架。 - 运行时191 通过、1 失败、54% 行覆盖率。唯一失败项
test_health_returns_degraded是一个过时测试而非产品缺陷——而它一直红着的事实恰恰证明这套套件从未被自动化运行过。 - 「构建坏了没人发现」的根因:没有 PR 门禁 CI。唯一的 workflow 是
docker-publish.yml(合并到main时构建并推送镜像),合并前没有任何东西运行pytest、tsc、next build或 lint。 - 现有测试集中在确定性算法核心(diff 引擎、schema),而把整个 I/O 面(DB、LLM、解析器、Playwright)全部 mock 掉了。因此覆盖在有的地方是真实的,但在用户真正受伤的地方(LLM 调用、PDF 渲染、上传解析)恰恰缺失。
- 需要两类测试且它们是两回事:确定性测试(管道正确性、LLM 被 mock、每次改动都跑)和Evals(LLM 输出质量、真实/录制 LLM、按需/夜间跑)。当前只有第一类且仅覆盖核心,第二类为零。
2. 现状评估:先量化,再下结论
原文档的评估命令不需要修改pyproject.toml——用临时插件即可得到覆盖数据:
cd apps/backend uv run --with pytest-cov pytest -q --cov=app --cov-report=term-missing # 192 tests · 191 passed · 1 FAILED · 54% coverage · ~6s结合 apps/backend/pyproject.toml 可以看到该套件的既有正确配置:asyncio_mode = "auto"(无需手动@pytest.mark.asyncio)、--strict-markers(未注册的 marker 直接报错)、unit/service/integration/eval四个显式声明的 marker,以及addopts = ["--strict-markers", "-v", "-m", "not eval"](默认排除 LLM-as-judge eval)。
2.1 那一个失败项是「金丝雀」
apps/backend/tests/integration/test_health_api.py::test_health_returns_degraded期望GET /health在 LLM 不健康时返回"degraded"。但 apps/backend/app/routers/health.py 重构后/health变成了纯 liveness 探针,永不调用 LLM(直接return HealthResponse(status="healthy")),就绪性(readiness)改由GET /status承担。测试从未同步更新。更讽刺的是它的兄弟用例test_health_returns_healthy是错误地通过了——它 mock 了check_llm_health,而该端点现在根本不再调用它,mock 是死的、断言是空心的。
结论:这里一个绿勾毫无意义,一个红叉无人看见——这正是生产事故背后的失败模式。在 apps/backend/app/routers/health.py 的源码注释里可以印证这一设计决策:「Lightweight liveness check for Docker HEALTHCHECK. Does NOT call the LLM provider. Use GET /status for full LLM health.」
2.2 覆盖地图:哪些真实、哪些缺失
这是原文档给出的模块级覆盖基线表,逐行继承并标注含义:
| 模块 | 覆盖 | 解读 |
|---|---|---|
services/improver.py(diff 引擎) | 84% | ✅ 真正扎实——路径解析、apply/verify diffs、skill 门控 |
schemas/models.py | 88% | ✅ 真实 |
services/refiner.py | 72% | ✅ 尚可 |
routers/config.py | 53% | 🟡 仅契约级 |
llm.py | 47% | 🟡 纯函数辅助已被测;真实请求 +check_llm_health+ Ollama 路径未测 |
routers/enrichment.py | 38% | 🟡 仅测了 regenerate 匹配,其余被 mock |
config_cache.py | 38% | 🔴 |
database.py | 34% | 🔴 此基线下真实 DB 未被执行——集成测试 mock 了db(Phase 4 & 7 已改) |
services/cover_letter.py | 26% | 🔴 完全未测 |
services/parser.py | 20% | 🔴 上传→markdown→JSON 未测,连纯日期恢复都未覆盖 |
pdf.py(渲染) | 20% | 🔴 「简历渲染不出来」这一类的源头 |
routers/resumes.py | 18% | 🔴 最大文件(1,796 LOC):tailor + PDF + CRUD 几乎全裸 |
2.3 关于集成测试的结构性真相(192 测试基线时点)
在 192 测试基线时,每一个apps/backend/tests/integration/*测试都 patch 了app.routers.<x>.db以及 LLM/解析调用。它们验证的是状态码、请求校验、响应形状和路由分支逻辑(如 API-key 掩码、regenerate 回退匹配)——是有价值的契约测试;但它们没有证明数据库真的持久化、Playwright 真的渲染、markitdown 真的解析、任何 provider(包括 Ollama)真的响应。(Phase 4 与 7 之后新增了真实 SQLite 的isolated_db持久化及 pipeline/tracker 集成测试。)
3. 框架决策:保留 pytest,增量补齐
原文档的决策明确:保留pytest+pytest-asyncio+httpx(它已正确配置了asyncio_mode=auto、严格 markers、unit/service/integrationmarkers),按需增量添加:
| 需求 | 工具 | 为什么 |
|---|---|---|
| 覆盖作为可追踪数字 | pytest-cov | 量化差距与增量,停止猜测 |
对假 provider(含 Ollama)测真实llm.py | respx(或pytest-httpx) | 在 HTTP 传输层 mock,让真实的 routing/normalization 代码跑起来——回归「Ollama 不工作」的唯一方式 |
| PDF 渲染证明 | Playwright(已是依赖) | 一条 smoke test → 从 print 路由得到真实 PDF 字节 |
| Prompt/skill 质量 | 仓库内eval harness | Golden fixtures + 结构化 scorer + 可选 LLM-as-judge |
| 推送门禁(本地,替代 PR CI) | pre-pushgit hook(.githooks/) | 跑后端套件 + locale parity,红则阻止推送;无 PR 触发 CI——见 §5 Phase 6 |
在 apps/backend/pyproject.toml 中可以看到这些工具已作为可选依赖落定:dev = ["pytest>=8.0.0", "pytest-asyncio>=0.24.0", "httpx>=0.28.0", "respx>=0.21.1"],另有独立可选组e2e-monitor = ["pypdf>=4.0.0", "httpx>=0.28.0"]。
3.1 确定性测试 vs Evals:关键区分
- 确定性测试(Deterministic test)——LLM 被 mock,对已知响应断言代码行为。快,每次改动都跑。回答的是「管道正确吗?」
- Eval——真实(或录制)LLM 调用按 rubric 打分。非确定性、花钱花时间,夜间/按需运行,绝不进 PR 门禁。回答的是「这次 prompt 改动让输出变好了吗?」
「我的 prompt 改动是否有帮助」无法用确定性测试回答——你需要 evals;反过来,也绝不应拿非确定性 eval 去卡 PR。两层分开,各司其职。
3.2 Prompt 链("skills")及每一阶段如何被测试
原文档给出了完整的技能流水线:
upload → parse_resume_to_json → extract_job_keywords → generate_skill_target_plan → verify_skill_target_plan (verify = 纯、确定性门) → generate_resume_diffs [strategy: keywords | nudge | full] → apply_diffs (纯) → render_resume_pdf对每一阶段:
- 确定性层——与措辞无关、必须成立的结构性不变量:合法 JSON/schema、不捏造雇主/日期(真实性规则)、每个 section 都被保留、JD 关键词确实出现在输出中、diff 路径可解析。绝大多数「prompt 改动搞坏了什么」的回归在这里被免费拦住。
- Eval 层——golden
(resume, job_description)fixtures → 用真实模型跑该阶段 → 用 rubric 打分(启发式 + LLM-as-judge)。跨时间与跨 prompt 编辑追踪质量。
这一分层在 apps/backend/tests/evals/scorers.py 有完整实现:五个纯函数 scorer(详见下文 §6)零 LLM、零网络、零磁盘,构成第一道廉价防线。
4. 什么是「验证我们最近的工作」:三种具体机制
对本次倡议中的每一次变更,原文档要求三件事:
- 覆盖增量(Coverage delta)。每个批次报告其触及模块的前后覆盖数字。要数字,不要感觉。
- 反剧院检查(Anti-theater check)。对关键逻辑的新测试,确认当代码被破坏时该测试确实失败(一次快速手动变异)。这是
test_health_returns_healthy「错误地通过」陷阱的解毒剂。 - 钉住近期 PR 的回归测试。第一批新覆盖刻意锁定最近交付的行为,让「我们最近的工作」拥有安全网:
_normalize_api_base——/v1/v1重复路径去重与 OpenAI 保持原样(issue #751)。resolve_api_key—— 安全规则:ollama/openai_compatible不得回退到环境变量LLM_API_KEY(防止付费 key 泄露给本地服务器)。get_model_name——ollama_chat/前缀与 OpenRouter 嵌套前缀。- 上传时空提取文本的拒绝(
resumes.py:546,PR #794,即 apps/backend/app/routers/resumes.py)。 restore_dates_from_markdown—— 月份在 LLM 解析后幸存。
这些纯函数回归测试落在 apps/backend/tests/unit/test_llm_providers.py:例如get_model_name(_cfg("ollama", "llama3")) == "ollama_chat/llama3"、OpenRouter 的openrouter/anthropic/claude-3.5-sonnet嵌套前缀、以及「不双重加前缀」的守卫——每一条都直接对应上表的一次生产事故或安全问题。
5. 分阶段路线图(Phase 1–7)
原文档以图例(✅ done · 🚧 in progress · ⬜ planned)完整记录了每一阶段的产出与验证数字,逐项继承如下:
Phase 1 — 基础 + 廉价确定性覆盖(PR #820 →dev)✅ COMPLETE
- ✅ 审计 + 本文档
- ✅ 让套件变绿(修复过时的
health测试;liveness vs readiness) - ✅
llm.pyprovider/Ollama 纯函数回归测试(apps/backend/tests/unit/test_llm_providers.py) - ✅
parser.py纯测试(日期恢复,apps/backend/tests/unit/test_parser.py)+ 空文本拒绝(apps/backend/tests/integration/test_upload_api.py) - ✅ 真实 SQLite
database.pyCRUD 测试(apps/backend/tests/unit/test_database.py) - ✅ 验证:192 → 265 测试、1 个静默失败 → 0、覆盖 54% → 58%(database 34→96%、parser 20→72%、llm 47→55%、health 重新有意义)。反剧院变异检查通过。
Phase 2 — 传输契约测试(LLM/Ollama)✅ COMPLETE(apps/backend/tests/integration/test_llm_contract.py,8 个测试)
- ✅
respx支撑:对假 Ollama + OpenAI-compatible HTTP 服务器走真实complete/complete_json/check_llm_health(base-URL 处理 #751、线上 JSON 提取、thinking-tag 剥离、健康检查错误码映射 + 密钥清洗)。发现:litellm 1.86 默认用 respx 看不见的 aiohttp 传输 → 测试设置disable_aiohttp_transport;Ollama 发出两次调用(/api/show探针 +/api/chat)。llm.py55% → 74%。
test_llm_contract.py的实现细节值得一提:每个测试都是真实的 respx HTTP 测试——litellm 的客户端真的序列化请求、经 httpx 传输发出、解析 mock 响应,全程不 mockrouter.acompletion/litellm.acompletion边界。其 autouse fixture_litellm_httpx_transport解释了一个真实世界的坑:litellm 1.86 默认的LiteLLMAiohttpTransport会让请求绕过 respx 直飞真实网络,必须monkeypatch.setattr(litellm, "disable_aiohttp_transport", True)强制落回 httpx,并 flushin_memory_llm_clients_cache。TestOllamaTransport还验证了关键行为:能力探针永远打localhost:11434/api/show,而真正的补全必须打到用户配置的{api_base}/api/chat——测试断言http://ollama.test:11434/api/chat被命中,这正是「Ollama 配置了自定义地址却总连 localhost」类 bug 的回归网。TestCheckHealthTransport则覆盖了健康检查的密钥清洗:fake provider 在 401 错误体中回显sk-key,测试断言error_detail中原始 key 与部分前缀都不可见、必须出现<redacted>。
Phase 3 — 渲染安全网 ✅ COMPLETE(apps/backend/tests/integration/test_pdf_render.py,11 个测试)
- ✅ 真实 headless-Chromium 渲染自包含的
data:URL → 断言真实%PDF字节;纯辅助测试(format/margins);connection-refused →PDFRenderError映射。无 Chromium 时渲染测试干净地 skip。pdf.py20% → 54%。
Phase 4 — 端到端 pipeline ✅ COMPLETE(apps/backend/tests/integration/test_pipeline_e2e.py,5 个测试)
- ✅ 真实 routers + 真实临时 DB(
isolated_db),每个 LLM 边界被 mock:upload → jobs → fetch以及preview→confirm 定制握手。断言真实持久化状态(master 不变量、parent_id关联、improvements记录)。resumes.py18% → 53%。
这里的isolated_dbfixture 在 apps/backend/tests/conftest.py 有完整实现:用Database(db_path=tmp_path / "isolated_db.db")替换全局db单例,并monkeypatch掉app.database及resumes/jobs/enrichment/config/health/applications/resume_wizard七个 router 模块中导入的db。fixture 注释强调了一个 SQLite 陷阱:必须用临时文件而非:memory:,因为连接池会给每个连接独立的 in-memory DB,async + sync 两套 engine 将无法共享状态。同文件还提供了sample_resume(完整ResumeData兼容字典)、sample_job_keywords、sample_changes(覆盖 replace/append/reorder 全部 action 类型的ResumeChange列表)等共享夹具。
Phase 5 — Eval harness(结构化 + LLM-as-judge)✅ COMPLETE(apps/backend/tests/evals/,31 个 scorer 测试 + 1 个门控 judge)
- ✅ 纯结构化 scorer(
sections_preserved、no_fabricated_employers、jd_keywords_present、is_valid_resume、personal_info_unchanged)+ golden fixtures,每个都在好与坏输入上被验证。 - ✅ LLM-as-judge 标记为
@pytest.mark.eval,使用开发者自己配置的 key,被默认运行排除(addopts -m "not eval");按需uv run pytest -m eval运行。无 key 时干净 skip。
apps/backend/tests/evals/README.md 给出了 scorer 的完整语义表:sections_preserved保证有内容的顶级 section 在定制后不消失;no_fabricated_employers逐条比对workExperience中公司名、返回捏造的雇主列表(空列表 = 真实);jd_keywords_present返回 JD 关键词实际出现在定制简历中的比例(0–1,大小写不敏感子串匹配,空关键词列表恒为 1.0);is_valid_resume用ResumeData.model_validate校验;personal_info_unchanged要求身份块逐字节不变。其测试test_scorers.py对每个 scorer 都构造了已知坏输入证明其真的会开火(删掉一个 section →False、编造公司 → 被返回、改名字 →False)——这就是反剧院的证据。golden fixtures 位于tests/evals/golden/cases.py的GOLDEN_CASES列表,每个条目包含original/job_description/jd_keywords/tailored_good/tailored_bad五要素,且要求tailored_good对每个关键词都达到 1.0、tailored_bad故意违反至少一条不变量,追加新用例即被参数化测试自动拾取。
Phase 6 — 本地 pre-push 门禁(替代 PR CI)✅ COMPLETE(.githooks/pre-push)
- ✅ 版本化的
pre-push钩子运行后端套件 + 免 Node 的 locale-parity 检查,红则阻止推送。每克隆激活一次:git config core.hooksPath .githooks;绕过:git push --no-verify。见 .githooks/README.md。 - ✅刻意避免 GitHub Actions PR 门禁——仓库外部贡献者 PR 流量大,PR 触发 CI 会对每一个(含不可信代码)都跑一遍。本地钩子以零成本为维护者自己的推送守住
dev/main的绿。 - ⬜(可选,未来)基于 Node 的
tsc/next build检查——因 nvm-in-hook 脆弱性而推迟;纯 Python 的 locale-parity 守卫已覆盖已知的 i18n 破坏。
.githooks/pre-push 的实际逻辑:set -uo pipefail下依次运行三件事——①uv run pytest -q -p no:cacheprovider(后端,uv不存在则报错并置 status=1);②python3 scripts/check_locale_parity.py(纯 Python,验证apps/frontend/messages/*.json与en.json结构一致,这正是曾让next build在合并后才炸掉的 i18n 不匹配);③vitest run(仅当node与本地 vitest 二进制都存在时执行,否则警告跳过)。全部检查总是运行以一次看到所有失败;任一失败即exit 1中止推送。
Phase 7 — SQLite 持久化 + tracker + 加密 key 覆盖(PRs #841 + #843 →main)✅ COMPLETE
- ✅ 持久层从 TinyDB 迁到SQLite(async SQLAlchemy);
conftest.py::isolated_dbfixture 现跨所有 router 模块替换为可丢弃的临时文件 SQLiteDB(不再是 TinyDB),apps/backend/tests/unit/test_database.py演练真实 SQLite CRUD(含TestApplications)。 - ✅ 新 tracker 覆盖:
apps/backend/tests/integration/test_applications_api.py(CRUD、列分组、删除简历后的 detail 容错、批量移动/删除)与apps/backend/tests/integration/test_tracker_autocreate.py(确认一次定制自动创建applied卡片)。 - ✅ 加密的按 provider API key:
apps/backend/tests/unit/test_crypto.py(Fernet 加密/解密往返 + 掩码)。 - ✅
/status优雅降级(#843):apps/backend/tests/integration/test_health_api.py扩展——每项检查互相隔离,单个探针失败返回 200 + partial/degraded 状态而非 500。
这在 apps/backend/app/routers/health.py 有直接源码对应:get_status将 LLM 健康探针与数据库统计各自包在独立的 try/except 中,任一个失败只降级自己的字段,_EMPTY_DB_STATS兜底保证/status仍能响应(degraded)而非 500;最终status字段由llm_healthy and has_master_resume计算为ready或setup_required。
- ✅ 验证:默认
uv run pytest数量现为~444(此前 ~320)。respx仍为llm.pymock HTTP 传输层。
Phases 1–7 之后的结果
192 → ~444 确定性测试(+ 1 个 opt-in LLM-judge eval),0 失败。Phases 1–5 由并行子代理构建(每阶段一个、严格文件所有权),使用dispatching-parallel-agents技能;Phase 7 跟随 TinyDB→SQLite 迁移(PRs #841 + #843)。
6. 如何运行
原文档给出的完整命令集(在apps/backend下执行):
cd apps/backend # 完整确定性套件(LLM-judge evals 通过 addopts -m "not eval" 自动排除) uv run pytest # 覆盖率(临时插件,不改 pyproject) uv run --with pytest-cov pytest -q --cov=app --cov-report=term-missing # 按需的 prompt 质量 evals——结构化 scorer 总是运行; # LLM-judge 仅在配置了 LLM key 时运行(使用开发者自己的 key),否则跳过 uv run pytest -m eval # 单个模块 uv run pytest tests/unit/test_parser.py -q注:
uv run pytest不受项目 nvm/npm 约束影响——它纯 Python。前端tsc/build/lint 分开运行,不在本后端阶段范围内。
uv run pytest -m eval的行为细节(来自apps/backend/tests/evals/README.md):无 key 的干净运行会显示 scorer 测试通过 + judge 测试skipped(_needs_key()是测试第一行,keyless 环境永远不会发出未门控的真实调用);要真正运行 judge,按运行应用的方式配置 provider/key(env 或 Settings UI →data/config.json)后重跑即可。
7. 决策日志(Decisions log)
| 日期 | 决策 | 理由 |
|---|---|---|
| 2026-05-30 | 以dev而非main作为本倡议基线。dev←main同步后从dev切分支,工作合回dev。 | 用户指示——在到达main之前在dev上批量完成这项工作。 |
| 2026-05-30 | 暂不引入 CI workflow(仅测试)。 | 用户指示。CI 是 ROI 最高的修复,但它是独立的显式决策(且.github/workflows/受变更控制)。 |
| 2026-05-30 | Eval 层 =结构化 + LLM-as-judge,judge 使用开发者提供的 LLM key,缺 key 时跳过。 | 用户指示——开发者(通常是维护者)提供 key,因此配置后接受真实 LLM 打分。 |
| 2026-05-30 | 保留pytest;新增respx、pytest-cov、Playwright smoke、eval harness。 | 现有框架是对的;补缺口而不是换框架。 |
| 2026-05-30 | 用本地pre-push钩子做门禁,而非 PR 上的 GitHub Actions。 | 维护者外部 PR 流量大;PR 触发 CI 会对所有 PR(含不可信代码)都跑。本地钩子以零成本让维护者自己的推送守住dev/main绿——后端套件 + 免 Node 的 locale parity——使用.githooks/+core.hooksPath。 |
8. 前端测试套件
apps/frontend使用vitest + Testing Library(jsdom)——运行npm run test(或./node_modules/.bin/vitest run)。后端同样的严谨度被应用:先评估现状(一个 65 测试的绿套件,覆盖download-utils与两个组件),再覆盖最高价值的未测逻辑。
新增(apps/frontend/tests/):
i18n-utils.test.ts——t()引擎(getNestedValue点路径 + 缺 key 回退、applyParams替换)。i18n-locale-parity.test.ts——构建破坏的套件内守卫:每个messages/*.json必须与en.json结构一致(镜像scripts/check_locale_parity.py)。已验证反剧院(向en.json加一个 key 会让全部四个 locale 失败)。keyword-matcher.test.ts—— JD↔简历关键词提取/分段/匹配统计。section-helpers.test.ts—— section 排序、自定义 section ID、仅本地化未改动的默认值。html-sanitizer.test.ts—— DOMPurify XSS 白名单(strong/em/u/a)。api-client.test.ts——lib/api/clientURL 解析 + 超时/AbortError(fetch被 stub)。
净效果:65 → 117 前端测试,全部绿。pre-push门禁在 Node 可用时运行该套件;完整的tsc/next build门禁仍是未来工作(nvm-in-hook 脆弱性)。
9. 未决问题 / 未来
- ✅
前端 locale-parity 测试—— 已完成(i18n-locale-parity.test.ts+ 钩子里的scripts/check_locale_parity.py)。 - 一旦 I/O 面被广泛覆盖,再决定每个模块的覆盖下限(避免用单一全局 % 掩盖缺口)。
- Node-aware 的
tsc/next build门禁(捕获 locale drift 之外的 TS 错误)——推迟;需要可靠的 node-in-hook。 - 若重新考虑 GitHub Actions,只对
dev/main的 push 运行(不对 PR)。
10. Agentic 端到端监控(按需、仅报告)
在确定性套件与本地 pre-push 门禁之上,还有一个agentic E2E monitor——一个 opt-in、按需的 harness,驱动真实运行的应用(master resume → 3–4 份定制变体 → PDFs),捕获持久化的证据包(日志 + 每个中间 JSON + PDFs),并用 Claude Code skill 以三个运行时任务评判:输出质量、flow/render 完整性、provider 真实性。它是报告而非门禁——只提供信息、从不阻止推送、永不接入 CI。
- 设计:docs/superpowers/specs/2026-06-01-agentic-e2e-monitor-design.md;计划:docs/superpowers/plans/2026-06-01-agentic-e2e-monitor.md;harness 与操作手册:apps/backend/e2e_monitor/README.md。
- OSS 安全:harness 依赖是可选的额外项(
uv sync --extra dev --extra e2e-monitor),每一步都被RM_E2E_MONITOR=1+ 已配置 key 门控,可运行 skill 被 gitignore(其源码是已提交的 apps/backend/e2e_monitor/AGENT_PLAYBOOK.md)。开发者真实 SQLite DB 永不被触碰(隔离的DATA_DIR)。 - 运行:
cd apps/backend && RM_E2E_MONITOR=1 uv run python -m e2e_monitor sweep,然后bash e2e_monitor/install_skill.sh并调用monitor-e2eskill 生成报告。
结语:这套策略的通用价值
Resume-Matcher 的测试治理实践可以被提炼为四条可移植的原则:先量化后整改(覆盖矩阵而非印象)、确定性测试与 Eval 严格分层(前者进门禁、后者按需跑)、在真实传输层复现用户报障(respx而非 mock 内部边界)、用本地钩子替代昂贵的 PR CI(把守维护者自己的推送而不拖累外部贡献者)。从「192 个测试、1 个看不见的失败、54% 覆盖」到「~444 个确定性测试、0 失败、I/O 面逐步补全」,这份 living document 本身就是一个可回放、可验证的整改样本——任何「测试存在却从未被执行」的仓库,都可以按同样的节奏从审计开始,走出测试剧院。
【免费下载链接】Resume-MatcherThe #1 AI Harness for Building Resumes, PDFs, Cover Letters & more, locally with 100+ LLMs support.项目地址: https://gitcode.com/GitHub_Trending/re/Resume-Matcher
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考