news 2026/9/26 10:19:19

【skills】AI测试:Markdown spec 配 TaoToken,30秒生成 pytest 并跑通 API/UI/CI

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【skills】AI测试:Markdown spec 配 TaoToken,30秒生成 pytest 并跑通 API/UI/CI

1. 为什么我又把 pytest 脚本删了重写

写 pytest 的人大概都经历过这个循环:接口文档更新一版,测试脚本跟着改一轮;UI 改了个按钮文案,定位器全挂;CI 上跑出来的失败,一半是用例本身写错了断言。我统计过自己上一个项目,纯手写 pytest 用例的维护成本,大概占了整个测试工作量的六成以上,真正用来设计测试场景的时间反而被压缩得很少。

这篇要聊的解法是:把测试设计从代码里抽出来,写进 Markdown spec,让生成器读 spec 直接产出可运行的 pytest 脚本,覆盖 API、UI、CI 三类场景。核心检索词就三个——pytest、Markdown spec、自动生成。适合谁?适合已经在用 pytest 但被重复劳动拖住的测试同学,也适合想把测试接进 CI 但不知道从哪下手的后端/全栈。

整条链路里,模型调用这一环我用 TaoToken 统一收口:一个 Key、一个 API 通道,本地生成脚本时用它做复杂用例补全,CI 里也能复用同一套配置,不用在多个平台之间来回切。下面按「问题场景 → TaoToken 前置 → 可复制配置 → 验证跑通 → 排错 → 下一步」的顺序讲,每一步都能直接抄。

2. TaoToken 前置:把模型调用收成一个通道

2.1 为什么测试链路也需要统一 Key

Markdown spec 生成 pytest 有两种模式:纯模板展开(不调模型)和 AI 辅助补全(调模型)。前者快,后者能处理复杂业务逻辑。问题在于,AI 辅助那一步如果 Key 散落在各个工具里,CI 上就会变成一堆环境变量地狱。

TaoToken 在这里的角色是「统一入口」:官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址 https://taotoken.net/api 。你只需要在配置里写一次 base_url 和 api_key,本地脚本、Cursor、CI runner 全部复用。

2.2 拿 Key 与选通道

登录后进控制台,在 API Keys 页面创建一个 Key:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。创建时建议按用途命名,比如pytest-spec-local和pytest-spec-ci,方便后面在 CI secret 里区分。

如果你只是想让 spec 生成器补全用例,用模型对话通道就够:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。如果你打算把生成 + 执行 + 修复做成长期跑的 Agent 流程,那 Coding Plan 更合适:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。

注意:Key 只存在本地.env或 CI secret 里,不要写进 spec 文件,spec 是要提交到 Git 的。

3. 可复制配置:config.toml 与 settings.json 骨架

3.1 config.toml:生成器读的主配置

生成器需要一个配置文件告诉它「模型通道在哪、spec 目录在哪、输出到哪」。下面这份可以直接复制,改掉路径即可:

# config.toml [model] provider = "taotoken" base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" # 从环境变量读,不硬编码 model = "claude-sonnet" # 按你控制台可用的模型名填 timeout = 60 [spec] input_dir = "./specs" output_dir = "./tests/generated" default_kind = "api_pytest" [runner] pytest_args = ["-v", "--tb=short"] base_url_env = "TEST_BASE_URL" [ci] report_dir = "./reports" upload_artifact = true

关键点:api_key_env指向环境变量名,而不是直接写 Key。这样本地和 CI 用同一份 config.toml,只是环境变量来源不同。

3.2 settings.json:给编辑器/Agent 用的通道配置

如果你在 Cursor 或类似编辑器里让 AI 读 spec 生成脚本,需要一个 settings.json 告诉它走哪个通道:

{ "taotoken": { "baseUrl": "https://taotoken.net/api", "apiKeyEnv": "TAOTOKEN_API_KEY", "defaultModel": "claude-sonnet", "endpoints": { "chat": "/v1/messages", "models": "/v1/models" } }, "pytest": { "specDir": "./specs", "generatedDir": "./tests/generated", "baseUrlEnv": "TEST_BASE_URL" } }

两份配置的分工:config.toml 给本地生成脚本和 CI 用,settings.json 给编辑器里的 AI 辅助用。两者共享同一个TAOTOKEN_API_KEY环境变量,不重复维护。

3.3 环境变量落地

# 本地 export TAOTOKEN_API_KEY="你的Key" export TEST_BASE_URL="http://localhost:8899" # CI 里放到 repository secret,名字保持一致

4. spec 示例文件与生成后的 pytest

4.1 API spec:一个文件描述一组用例

spec 就是带 YAML frontmatter 的 Markdown。下面这份描述用户接口的冒烟测试:

--- kind: api_pytest base_url: http://localhost:8899 cases: - id: TC-001 method: GET path: /api/users expect_status: 200 - id: TC-002 method: POST path: /api/users json_body: name: "张三" email: "zhangsan@example.com" expect_status: 201 --- # 用户接口冒烟测试 覆盖列表查询与创建两个核心路径。

生成命令:

python codegen/run_spec.py specs/api_smoke.md --config config.toml

产出的 pytest 脚本大致长这样:

# Auto-generated by spec runner import os import pytest import requests BASE_URL = os.environ.get("TEST_BASE_URL", "http://localhost:8899") def test_tc_001(api_session): """TC-001: GET /api/users -> 200""" r = api_session.get(BASE_URL.rstrip("/") + "/api/users", timeout=30) assert r.status_code == 200, r.text[:800] def test_tc_002(api_session): """TC-002: POST /api/users -> 201""" r = api_session.post( BASE_URL.rstrip("/") + "/api/users", json={"name": "张三", "email": "zhangsan@example.com"}, timeout=30, ) assert r.status_code == 201, r.text[:800]

4.2 UI spec:用语义定位代替 CSS 选择器

UI 测试最容易挂的就是定位器。spec 里用 label/role 这类语义定位,生成出来的 Playwright 脚本稳定性会好很多:

--- kind: ui_pytest_playwright base_url: http://localhost:5569 steps: - action: goto path: /login - action: fill l1_label: "用户名" value: "admin" - action: fill l1_label: "密码" value: "admin123" - action: click l1_role: button l1_name: "登录" expect: - type: url_regex pattern: "/(dashboard|home)$" --- # 登录流程测试

生成后执行:

pytest tests/generated/test_ui_login.py -v

4.3 复杂用例:让模型补边界场景

模板展开只能覆盖你写进 spec 的用例。边界值、异常分支这类,可以让模型读 spec 后补全。这一步走 TaoToken 的模型对话通道,配置已经在 config.toml 里了:

python codegen/run_spec.py specs/api_smoke.md \ --config config.toml \ --enrich \ --prompt "补充余额不足、重复提交、超时三类异常用例"

生成器会把 spec 内容 + 提示词发给 TaoToken,拿回补充后的用例再展开成 pytest。你可以在模型对话页面先手动试一下提示词效果:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。

5. 验证请求与成功结果

5.1 本地跑通

# 1. 生成 python codegen/run_spec.py specs/api_smoke.md --config config.toml # 2. 执行 pytest tests/generated/test_api_smoke.py -v # 期望输出 # tests/generated/test_api_smoke.py::test_tc_001 PASSED # tests/generated/test_api_smoke.py::test_tc_002 PASSED # ===== 2 passed in 0.84s =====

5.2 验证模型通道是否通

生成器调模型那一步如果失败,先单独验证通道:

curl -s https://taotoken.net/api/v1/models \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" | head -c 400

返回模型列表就说明 Key 和通道都正常。如果这里就报 401,问题在 Key;如果报连接错误,检查 base_url 有没有写错。

5.3 CI 触发

GitHub Actions 里最小可用的一段:

name: pytest-spec-ci on: push: branches: [main] paths: ["backend/**", "specs/**"] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" - run: pip install PyYAML pytest requests pytest-playwright - run: playwright install chromium - run: python codegen/run_spec.py specs/api_smoke.md --config config.toml env: TAOTOKEN_API_KEY: ${{ secrets.TAOTOKEN_API_KEY }} - run: pytest tests/generated -v env: TEST_BASE_URL: http://localhost:8899

提交一次代码,Actions 页面能看到 pytest 输出,全绿即链路通。

6. 本篇常见错排查

6.1 生成脚本报 Key 缺失

现象:TAOTOKEN_API_KEY not found。原因通常是 config.toml 里写了api_key_env但环境变量没导出。检查echo $TAOTOKEN_API_KEY是否有值。CI 里确认 secret 名字和 config.toml 里写的一致。

6.2 pytest 收集不到用例

现象:no tests ran。多半是生成目录不在 pytest 的收集路径里。检查pytest.ini或pyproject.toml里的testpaths,把tests/generated加进去。另一个可能是文件名没以test_开头,生成器默认会加前缀,如果你手动改了文件名要注意。

6.3 UI 测试定位超时

现象:Timeout waiting for locator。先确认base_url指向的服务真的起来了,再确认 label 文案和页面完全一致(包括空格)。语义定位对文案敏感,文案改了 spec 也要改。如果页面是异步渲染,在 spec 的 step 里加等待动作,而不是在生成后的脚本里手改。

6.4 CI 里模型调用超时

现象:本地能生成,CI 卡在 enrich 步骤。CI runner 网络出口和本地不同,先跑 5.2 的 curl 验证。如果 curl 通但生成器超时,把 config.toml 的timeout调大,或者把 enrich 拆成单独一步、失败不阻塞主流程。

6.5 生成脚本覆盖了手写用例

现象:重新生成后手写的补充用例没了。生成目录和手写目录要分开,tests/generated只放生成产物,手写用例放tests/manual。CI 里两个目录都跑,互不干扰。

7. 下一步:把生成链路接进长期流程

到这一步,你已经有了:Markdown spec → pytest 脚本 → 本地跑通 → CI 触发 的完整闭环。接下来两个方向可以按需选。

如果你主要想让模型帮你持续补用例、修失败断言,把生成 + 执行 + 修复做成一个能长期跑的 Agent 流程,用 Coding Plan 更省心:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。它适合这种「反复调用、上下文要延续」的场景。

如果你只是想先把接入细节吃透,比如 Key 怎么管、base_url 怎么配、不同模型的 endpoint 差异,直接翻接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。文档里有各语言的调用示例,对着改 config.toml 就行。

最后给一个我踩过的坑:spec 文件一定要进 Git,但生成出来的 pytest 脚本建议也进 Git。原因很简单——CI 上如果生成步骤挂了,你至少还有上一版可运行的脚本兜底,不至于整条流水线红掉。生成是加速手段,不是唯一依赖。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 10:18:27

Hindsight 部署在 NAS 上并接入 Hermes:Docker 配置与 API 验证全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 10:18:08

web.xml 报 content is not allowed in prolog:从 BOM 到 UTF-8 的排查与修复

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 10:18:02

windows下RabbitMQ的使用(3)——Spring Boot集成RabbitMQ(Hello World模式)

前面两篇文章: windows下RabbitMQ的使用(1)——下载与安装 windows下RabbitMQ的使用(2)——安装插件与创建队列 RabbitMQ的版本号是4.3.0。 在整合之前,需要知道一些名词和工作模式。 RabbitMQ 就像是一个超级邮差兔,不过它不送胡萝卜&…

作者头像 李华
网站建设 2026/9/26 10:17:54

AI Agent 面试题 238:System Prompt的版本管理和A/B测试策略

🔥 AI Agent 面试题 238:System Prompt的版本管理和A/B测试策略摘要:本文深入解析了「System Prompt的版本管理和A/B测试策略」这一 AI Agent 领域的核心面试题。文章从 System Prompt 工程 的基本概念出发,系统性地剖析了 版本管…

作者头像 李华
网站建设 2026/9/26 10:17:42

多门店串口设备改造:IoT网关数量与部署位置规划方法

多门店的串口设备改造,听起来是个不大不小的项目,但真正落地时最容易在同一个地方翻车:IoT 网关数量算不准,部署位置定不下来。尤其是同时涉及电表、收银机、PLC、门禁这类老旧串口设备时,很多团队把大量精力花在协议解…

作者头像 李华