用 python-tdd-with-uv:让 AI Agent 按红-绿-重构写 Python

前言

让 AI 帮忙写 Python 时,常见问题不是「写不出来」,而是「一次写太多」。Agent 容易先堆实现、再补测试,或者一口气写一串尚未失败的用例,结果接口提前定死、测试只贴实现细节,后面改起来很痛。

TDD(测试驱动开发)本来就是用来约束这种冲动的:先写一个失败的测试,再写刚好够通过的代码,再重构。Astral 出品的 uv 又把依赖安装、虚拟环境和命令执行收成一套很快的工具链。把这两件事写进一份可复用的 SKILL.md,就是 python-tdd-with-uv 要做的事——让 Cursor、Claude Code、Codex CLI 等支持 Agent Skills 的工具,在写 Python 时默认走「小步、先测、用 uv 跑」的流程。

这是什么

python-tdd-with-uv 是一份 Agent Skill,收录在 spencerpauly 维护的 awesome-cursor-skills 仓库中,路径为 resources/python-tdd-with-uv/。官方一句话定位是:用 uv 做包管理,在 Python 里做测试驱动开发,覆盖红-绿-重构循环、垂直切片,以及用 uv 初始化项目。

Skill 本体是标准的 SKILL.md(YAML frontmatter + 正文指令)。frontmatter 里 namepython-tdd-with-uvdescription 说明适用场景,并声明 user-invocable: true,因此除了 Agent 按描述自动选用外,也可以在对话里用 /python-tdd-with-uv 显式调用(具体以所用工具对 Skills 的支持为准)。

它解决的问题很具体:把「怎么立项、怎么加 pytest、怎么一轮只推进一个行为、怎么用 uv run 跑测试」写成 Agent 必须遵守的规则,而不是每次口头提醒。

核心能力

根据仓库中的 SKILL.md 原文,该 Skill 主要约束以下几件事。

  1. 用 uv 搭项目与测试依赖
    检查 uv 是否可用;没有 pyproject.toml 时用 uv init;用 uv add --dev pytest pytest-cov 加入开发依赖;用 uv run pytest --co 确认测试发现正常。

  2. 垂直切片式的红-绿-重构
    同一时间只允许一个失败测试:RED 写一个失败用例 → GREEN 写最少实现让它通过 → REFACTOR 在行为不变的前提下整理代码 → 再重复。禁止「先实现再补测」,也禁止一次写多个失败测试。

  3. 写代码前先做简短规划
    先回答:要改哪些接口(函数、类、API)?哪些行为最关键?能否做成可测设计(依赖注入、少用全局状态)?

  4. 测试写法与边界
    测试断言可观察行为,而不是实现细节;Mock 只用在系统边界(I/O、网络、时钟等)。推荐按 tests/test_<module>.py 用类分组相关行为。

  5. 统一用 uv run 执行
    所有命令走 uv run,不要手动 activate 虚拟环境;同时提交 pyproject.tomluv.lock

Skill 文末还指向了几份相关资料作延伸阅读:mattpocock 的垂直切片 TDD Skill、nizos/tdd-guard(用 hooks 强制 TDD)、以及 s2005/uv-skill(uv 工作流模式)。这些是参考链接,不是本 Skill 的内置脚本。

关于 uv 本身:它是 Astral(Ruff 同门)用 Rust 写的 Python 包与项目管理工具,官方文档称可替代 pip、pip-tools、poetry、virtualenv 等常见工具链的一部分,并提供跨平台的 uv.lock。本 Skill 并不重新发明 uv,只是把「TDD 节奏 + uv 命令约定」绑在一起,方便 Agent 执行。

安装与启用

手动放入项目(各工具通用)

Skill 的实质就是一个目录里的 SKILL.md。从官方仓库取出后,按工具约定放到对应目录即可。awesome-cursor-skills 的 README 说明:在 Cursor 中可复制到项目的 .cursor/skills/(或个人目录)下,由 Agent 自动发现。

# 示例:只拉取该 Skill 到当前项目(Cursor 项目级)
mkdir -p .cursor/skills/python-tdd-with-uv
curl -fsSL \
  https://raw.githubusercontent.com/spencerpauly/awesome-cursor-skills/main/resources/python-tdd-with-uv/SKILL.md \
  -o .cursor/skills/python-tdd-with-uv/SKILL.md

也可整仓克隆后,把 resources/python-tdd-with-uv/ 拷到本地 skills 目录。

Cursor 文档,Skills 会从下列位置加载(项目级 / 用户级):

位置 范围
.cursor/skills/.agents/skills/ 当前项目
~/.cursor/skills/~/.agents/skills/ 用户全局
.claude/skills/.codex/skills/ 及对应家目录路径 兼容 Claude Code / Codex

每个 Skill 应是「文件夹 + SKILL.md」,文件夹名与 frontmatter 里的 name 一致(此处为 python-tdd-with-uv)。

用 skills CLI 安装(Claude Code 等)

第三方目录 Claude Skills Hub 给出的安装示例为:

npx skills add spencerpauly/awesome-cursor-skills --skill python-tdd-with-uv --agent claude-code

该命令会把 Skill 装进当前项目的 .claude/skills/。若你使用 Codex 等其它 agent 标识,以 npx skills 当时支持的参数为准。

系统侧依赖:先装好 uv

本 Skill 假设本机已有 uv。可按 uv 官方安装说明 安装,例如 macOS / Linux:

curl -LsSf https://astral.sh/uv/install.sh | sh
uv --version

装好 Skill 之后,在 Agent 对话里直接说「按 TDD 用 uv 实现某某功能」,或输入 /python-tdd-with-uv,Agent 应读取该 Skill 并按其中步骤执行。

典型用法

下面流程均来自官方 SKILL.md,可直接复现。

1. 初始化项目与 pytest

uv --version

# 若还没有 pyproject.toml
uv init

uv add --dev pytest pytest-cov
uv run pytest --co

--co(collect-only)只收集用例、不执行,用来确认测试发现配置是否正常。

2. 按垂直切片推进一个行为

规划阶段先想清楚接口与关键路径,然后严格一轮只做一个失败测试。Skill 给出的循环是:

RED   → 为下一个行为写「一个」失败测试
GREEN → 写最少代码让它通过
REFACTOR → 清理结构,不改变行为
REPEAT

硬性规则包括:没有失败测试就不要写实现;每次改完都跑 uv run pytest;断言行为而非内部细节;Mock 仅用于 I/O、网络、时钟等边界。

3. 推荐的测试文件结构

# tests/test_<module>.py

class TestFeatureName:
    """Group related behaviors."""

    def test_does_expected_thing_when_given_input(self):
        result = function_under_test(input_value)
        assert result == expected

    def test_raises_when_given_invalid_input(self):
        with pytest.raises(ValueError):
            function_under_test(bad_input)

4. 常用测试命令

uv run pytest                      # 全部测试
uv run pytest tests/test_foo.py    # 单文件
uv run pytest -k "test_name"       # 按名称过滤
uv run pytest --cov=src            # 带覆盖率
uv run pytest -x                   # 遇失败即停

5. uv 日常命令速查

uv add <package>           # 添加依赖
uv add --dev <package>     # 添加开发依赖
uv remove <package>        # 移除依赖
uv sync                    # 按锁文件同步环境
uv run <command>           # 在托管环境中执行
uv lock                    # 重新生成锁文件

Skill 明确要求:始终用 uv run 执行命令,不要手动激活 venv;pyproject.tomluv.lock 一并提交,保证环境可复现。

适用场景与注意事项

比较合适的情况:

  • 用 AI Agent 从零搭 Python 小项目,希望默认走 pytest + TDD。
  • 给已有仓库补行为时,希望 Agent「一次只吃透一个切片」,避免大段投机实现。
  • 团队已经或准备统一用 uv 管理依赖与锁文件。

需要注意的限制:

  • 这是「流程指令」Skill,不是替你写好业务代码的框架;效果取决于 Agent 是否认真遵循 SKILL.md。
  • 本机必须先安装 uv;Skill 不会代替系统包管理器去装 uv。
  • 「一次只允许一个失败测试」会故意变慢一点——这是为了防止过度设计;若你明确只要快速草稿、不要 TDD,就不必启用该 Skill。
  • Mock 规则偏严:内部协作对象不该轻易 mock;若项目大量依赖复杂外部服务,需要先想好边界怎么切。
  • Skill 正文引用了 mattpocock/skills、tdd-guard、uv-skill 等延伸方案,但它们是独立项目,默认安装本 Skill 时并不会一并装上。

小结

python-tdd-with-uv 把两件近年 Python / AI 编程里很实用的约定绑在一起:一是红-绿-重构与垂直切片,二是用 uv 管依赖并用 uv run pytest 闭环验证。它来自 awesome-cursor-skills 的 Testing 分类,源文件在:

https://github.com/spencerpauly/awesome-cursor-skills/tree/main/resources/python-tdd-with-uv

SKILL.md 放进项目的 skills 目录(或按 CLI 装到 .claude/skills/),再让 Agent 做 Python 功能开发时,就能少写一点「请先写测试」的口头约束,多一点可复现的小步节奏。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜