资讯动态

SDD与TDD介绍

发布时间:2026/10/15 17:10:35 来源:尧图企业网站定制
AI 写代码越来越快但“快”不等于“对”。规范驱动开发SDD解决“做什么”测试驱动开发TDD解决“做对了没有”。两者结合才能让 AI 真正成为高效且可靠的开发伙伴。一、引子一个让所有开发者都头疼的场景假设你是一名后端开发产品经理走过来跟你说“做一个商品搜索功能用户输入关键词能搜到相关商品。”你点点头打开 AI 编码助手输入这句话。几秒钟后AI 给了你一段代码def search_products(keyword): return db.query(SELECT * FROM products WHERE name LIKE % keyword %)这段代码能跑吗能。但它有问题吗问题一大堆SQL 注入直接拼接字符串黑客输入 OR 11就能拖库。搜索范围不明只搜商品名还是也搜描述、分类、品牌排序规则不明按销量排按价格排按相关度排分页不明返回多少条超过怎么办空结果处理不明搜不到返回空列表还是报错性能问题LIKE %keyword%无法走索引商品上百万时直接拖垮数据库。大小写敏感搜iphone能不能搜到iPhone这些问题不是 AI 的错是需求没有说清楚。这就是今天要讲的两个核心方法论的起点SDDSpec-Driven Development规范驱动开发在写代码之前把“做什么”想清楚。TDDTest-Driven Development测试驱动开发在写实现之前把“做对了没有”定义清楚。AI 负责中间的代码生成而人守住需求和验证的两端。二、SDD先想清楚“做什么”2.1 什么是 SDDSDD 的核心思想是将结构化的规范作为“唯一事实来源”代码只是规范的一种实现形式。在 AI 开发中它相当于你和 AI 之间的一份精确“契约”。你不再对 AI 说“帮我写个搜索功能”而是说“这是搜索功能的完整规范请严格按照它生成测试和代码”。2.2 SDD 的四个阶段SDD 通常分为四个递进阶段每个阶段都有明确的产出物和验证检查点。阶段目标产出物关键问题指定Specify定义“要做什么”规范文档用户需要什么验收标准是什么边界在哪计划Plan确定“如何构建”技术方案用什么架构什么技术栈接口怎么设计任务Tasks拆解“具体步骤”任务清单先做什么后做什么每个任务怎么验证实现Implement编写并验证代码可工作代码代码是否符合规范测试是否通过2.3 阶段一指定——写一份好的规范这是最关键的一步。一份好的规范应该包含以下部分1总结Summary用一两句话从用户视角概括功能。## 总结 为电商网站增加商品搜索功能用户输入关键词后系统返回匹配的商品列表 支持按相关度、销量、价格排序支持分页支持按分类和价格区间筛选。2用户故事User Stories以“作为...我想要...以便...”的格式描述用户意图。## 用户故事 - US1作为买家我想输入关键词搜索商品以便快速找到想要的商品。 - US2作为买家我想按销量排序以便找到最受欢迎的商品。 - US3作为买家我想按价格区间筛选以便控制预算。 - US4作为买家我想看到搜索结果总数以便判断是否需要缩小范围。3验收标准Acceptance Criteria这是规范中最核心的部分。每条验收标准都必须可测试、无歧义。## 验收标准 - AC1输入关键词手机返回名称或描述中包含手机的商品按相关度降序排列。 - AC2搜索结果为空时返回空列表和总数 0HTTP 状态码 200。 - AC3关键词为空或只有空格时返回 400提示关键词不能为空。 - AC4关键词长度超过 100 字符时返回 400提示关键词过长。 - AC5默认每页 20 条最大 100 条超出时按最大值处理。 - AC6支持按销量降序排序参数 sortsales_desc。 - AC7支持按价格区间筛选参数 min_price 和 max_price价格单位为元最多两位小数。 - AC8搜索关键词不区分大小写iphone能搜到iPhone。 - AC9搜索结果必须防 SQL 注入关键词中的特殊字符需转义。 - AC10搜索接口响应时间在 100 万商品数据量下不超过 500ms。注意 AC9 和 AC10它们不是功能需求而是非功能需求。很多人写规范时只关注功能忽略了安全和性能结果上线后才发现问题。4边界情况Edge Cases边界情况是最容易被忽略、也最容易出 bug 的地方。## 边界情况 - 关键词包含前后空格应自动去除后再搜索。 - 关键词包含 SQL 特殊字符如单引号、双引号、百分号、下划线应转义后搜索。 - 关键词包含 emoji 或中文应正常搜索。 - 价格区间 min_price max_price 时返回 400提示价格区间不合法。 - 价格区间包含负数时返回 400。 - 页码超过总页数时返回空列表HTTP 状态码 200。 - 排序参数传入不支持的值时使用默认排序相关度不报错。 - 同时传入多个筛选条件时取交集。5非功能需求Non-Functional Requirements## 非功能需求 - 性能100 万商品数据量下搜索响应时间 P95 500ms。 - 安全防止 SQL 注入、XSS 攻击。 - 可用性搜索服务不可用时降级为返回热门商品。 - 可观测性记录搜索关键词、响应时间、结果数量便于分析。 - 兼容性支持 RESTful API返回 JSON 格式。2.4 阶段二计划——确定“如何构建”规范定义了“做什么”计划则详细阐述“如何做”。它将需求转化为具体的技术方案。## 技术方案 ### 架构 - Controller 层处理 HTTP 请求参数校验。 - Service 层业务逻辑搜索、排序、筛选。 - Repository 层数据访问使用 Elasticsearch 或数据库全文索引。 ### 技术选型 - 搜索引擎Elasticsearch 7.x支持分词、相关度排序、高亮。 - 参数校验使用框架自带的校验器如 Spring Validation、Pydantic。 - 缓存Redis 缓存热门搜索词的结果TTL 5 分钟。 - 分页使用 from size深分页使用 search_after。 ### 接口设计 GET /api/products/search 参数 - keyword: string, 必填, 1-100 字符 - sort: string, 可选, 枚举值: relevance_desc, sales_desc, price_asc, price_desc - min_price: decimal, 可选, 0 - max_price: decimal, 可选, 0 - page: int, 可选, 默认 1 - page_size: int, 可选, 默认 20, 最大 100 返回 { total: 1234, page: 1, page_size: 20, items: [ { id: ..., name: ..., price: 1999.00, sales: 5000, ... } ] }2.5 阶段三任务——拆解“具体步骤”将规范和技术计划分解为一系列可独立实现和验证的小任务。## 任务清单 - [ ] T001 搭建 Elasticsearch 环境导入商品数据验证搜索可用。 - [ ] T002 定义搜索接口的请求/响应 DTO添加参数校验。 - [ ] T003 实现关键词搜索AC1、AC8支持中文分词。 - [ ] T004 实现空关键词和超长关键词校验AC3、AC4。 - [ ] T005 实现空结果处理AC2。 - [ ] T006 实现分页AC5。 - [ ] T007 实现排序AC6。 - [ ] T008 实现价格区间筛选AC7处理边界情况。 - [ ] T009 实现 SQL 注入防护AC9。 - [ ] T010 性能优化确保 100 万数据下 P95 500msAC10。 - [ ] T011 编写集成测试覆盖全部 AC。 - [ ] T012 添加监控和日志。每个任务都标注了关联的验收标准。检查点逐条核对 AC 是否都有任务覆盖。2.6 阶段四实现——编写与验证按照任务清单逐个实现。在继续下一个任务之前必须根据规范验证当前任务的完成情况。这个阶段就是 TDD 发挥作用的地方下一节详细展开。2.7 规范是“活文档”需求变更时不能直接改代码而是更新规范文档。调整技术方案。生成新任务。重新实现并验证。这样规范、计划、任务、代码四者始终一致。规范不是写完就扔的文档而是贯穿整个开发周期的核心工件。三、TDD用测试验证“做对了没有”3.1 什么是 TDDTDDTest-Driven Development测试驱动开发是一种通过编写测试来驱动设计的开发方法。它的核心循环是红 → 绿 → 重构。阶段做什么关键点红Red写一个失败的测试定义下一个行为确认失败原因正确绿Green写刚好能通过测试的最少代码不许多写功能重构Refactor优化结构保持测试通过行为不变质量提升3.2 为什么 TDD 有效设计接口写测试时你必须思考入参、出参、异常和边界。写不出清晰的测试往往意味着需求本身没想清楚。安全网完善的测试让重构不再可怕。你可以放心地优化代码因为测试会告诉你有没有破坏行为。可执行文档测试就是最准确的行为说明。新成员看测试比看文档更靠谱。减少调试时间测试先失败再通过你确切知道哪行代码解决了问题。3.3 在 AI 辅助下执行 TDD关键原则不要让 AI 同时生成测试和实现。为什么因为 AI 会“迎合”自己写的实现。如果它先写实现再写测试测试往往只覆盖实现已经做到的事情而不是需求真正要求的事情。测试失去了独立验证的意义。正确做法是分步走第一步让 AI 写测试给 AI 的提示根据验收标准 AC1为商品搜索接口写一个集成测试。只写测试不要写实现。使用项目现有的测试框架。覆盖成功路径输入关键词手机返回名称或描述中包含手机的商品按相关度降序排列。AI 生成的测试以 Python pytest 为例def test_search_products_success(client, seed_products): AC1输入关键词返回匹配商品按相关度降序排列 response client.get(/api/products/search?keyword手机) assert response.status_code 200 data response.json() assert data[total] 0 assert len(data[items]) 0 # 验证每个结果都包含关键词 for item in data[items]: assert 手机 in item[name] or 手机 in item.get(description, ) # 验证按相关度降序假设相关度字段为 relevance_score scores [item[relevance_score] for item in data[items]] assert scores sorted(scores, reverseTrue)人工审查测试断言是否明确是。是否只测了一个行为是。测试名是否清晰是。是否依赖未实现的功能是但这是预期的。第二步运行测试确认失败pytest tests/test_search.py::test_search_products_success输出应该是失败红并且失败原因正确——比如“接口不存在”或“返回 404”而不是“测试写错了”。FAILED tests/test_search.py::test_search_products_success assert 404 200确认失败原因正确是因为功能没实现而不是测试本身有语法错误或导入错误。如果失败原因是测试写错了先修测试。第三步让 AI 写最小实现给 AI 的提示现在实现商品搜索接口只写让这个测试通过的最少代码。不要添加参数校验、分页、排序、筛选。那些是后面测试的事。AI 生成最小实现app.get(/api/products/search) def search_products(keyword: str): results es.search( indexproducts, body{ query: { multi_match: { query: keyword, fields: [name, description] } } } ) items [ { id: hit[_id], name: hit[_source][name], description: hit[_source].get(description, ), price: hit[_source][price], sales: hit[_source][sales], relevance_score: hit[_score] } for hit in results[hits][hits] ] return { total: results[hits][total][value], items: items }第四步运行测试确认通过pytest tests/test_search.py::test_search_products_success输出通过绿。第五步重构在测试的保护下优化代码结构。把 Elasticsearch 查询逻辑提取到SearchService。把响应构建提取到SearchResponseBuilder。统一错误处理。给 AI 的提示在不改变行为的前提下重构搜索接口把 Elasticsearch 查询逻辑提取到 SearchService把响应构建提取到 SearchResponseBuilder。保持测试通过。先提出方案等我确认后再改。运行测试确认仍然绿。第六步重复下一个验收标准AC3 空关键词返回 400写测试 → 失败 → 加校验 → 通过 → 重构。AC4 超长关键词返回 400写测试 → 失败 → 加校验 → 通过 → 重构。AC2 空结果返回 200写测试 → 失败 → 处理空结果 → 通过 → 重构。AC5 分页写测试 → 失败 → 实现分页 → 通过 → 重构。AC6 排序写测试 → 失败 → 实现排序 → 通过 → 重构。AC7 价格筛选写测试 → 失败 → 实现筛选 → 通过 → 重构。AC9 SQL 注入防护写测试 → 失败 → 加转义 → 通过 → 重构。AC10 性能写性能测试 → 失败 → 优化 → 通过 → 重构。每个循环只针对一个行为测试先失败实现最小化。3.4 为什么“先失败”这么重要如果你写了一个测试它直接通过了说明要么这个行为已经实现了那不需要再写要么测试写错了根本没有验证到你想验证的东西。只有先看到它失败并且失败原因正确你才能确信这个测试真的在验证新行为。3.5 测试的层次TDD 不只是单元测试还包括集成测试和端到端测试。不同层次的测试有不同的作用测试类型范围速度数量作用单元测试单个函数/类快多验证核心逻辑快速反馈集成测试多个模块/服务中中验证模块间协作接口契约端到端测试整个系统慢少验证用户场景最终保障在 TDD 中通常从单元测试开始逐步扩展到集成测试。对于 API 接口集成测试是主力。四、SDD 和 TDD 怎么配合4.1 上下游关系它们不是二选一而是上下游关系SDD写规范 → 定计划 → 拆任务 ↓ TDD写测试 → 写实现 → 重构 ↓ 重复下一个验收标准4.2 对比维度SDDTDD回答的问题要做什么做对了没有抽象层级需求/功能层面代码/行为层面主要产物规范文档测试用例适用场景需求模糊、多人协作、AI 辅助逻辑复杂、需要长期维护AI 协作方式AI 帮助澄清需求、生成计划AI 生成测试草稿和最小实现变更时先改规范再改代码先改测试再改实现4.3 完整工作流以一个完整的功能开发为例1. 产品经理提出需求“做一个商品搜索功能” ↓ 2. SDD 指定阶段和 AI 一起写规范 - 用户故事、验收标准、边界情况、非功能需求 - 人工审查确认无歧义 ↓ 3. SDD 计划阶段确定技术方案 - 架构、技术选型、接口设计 - 人工审查确认可行 ↓ 4. SDD 任务阶段拆解任务 - 每个任务关联验收标准 - 人工审查确认覆盖完整 ↓ 5. TDD 循环逐个任务实现 - 写测试 → 运行失败 → 写最小实现 → 运行通过 → 重构 - 重复直到所有验收标准覆盖 ↓ 6. 验证阶段对照规范逐条验证 - 所有测试通过 - 所有验收标准满足 - 必要时回写规范五、开发人员日常怎么执行5.1 接到新需求时不要直接打开 AI 说“帮我写个 XX 功能”。而是先写规范用户故事、验收标准、边界情况、非功能需求。让 AI 审查规范补充遗漏。确认技术方案和任务拆解。再进入 TDD 循环。时间分配建议需求分析和规范编写占 30%测试和实现占 50%重构和验证占 20%。5.2 写代码时从规范里选一条验收标准。让 AI 写测试人工审查。运行测试确认失败。让 AI 写最小实现。运行测试确认通过。决定是否重构。重复下一条。5.3 提交代码前所有测试通过。对照规范逐条验证验收标准。如果实现和规范有偏差先改规范再改代码。检查测试覆盖率确保核心逻辑都有测试。5.4 需求变更时先更新规范。再更新计划和任务。再写新测试。再改代码。确保旧测试依然通过。5.5 代码评审时检查代码是否偏离规范。检查测试是否覆盖了所有验收标准。检查边界情况是否处理。检查是否有未测试的新功能。六、AI 辅助的提示词模板6.1 写规范时我要做一个 [功能描述]。请帮我整理成规范包含用户故事、验收标准、边界情况、非功能需求。不要写代码。验收标准必须可测试、无歧义。6.2 审查规范时请审查这份规范找出遗漏的边界情况、前后矛盾的地方、不够明确的验收标准、缺失的非功能需求。6.3 写测试时根据验收标准 AC_X为 [功能] 写一个测试。只写测试不要写实现。覆盖成功路径和指定的异常情况。测试必须能独立运行不依赖其他测试的状态。6.4 写实现时现在实现 [功能]只写让当前失败的测试通过的最少代码。不要添加未测试的功能。使用现有的 service 和错误处理。6.5 重构时在不改变行为的前提下重构 [文件/模块]保持所有测试通过。先提出方案等我确认后再改。6.6 验证时对照规范中的验收标准逐条检查实现是否满足。列出未满足或不确定的项。七、常见误区误区一SDD 就是写文档浪费时间错。SDD 的规范是给 AI 看的“契约”不是给领导看的汇报材料。它直接决定 AI 生成的代码是否正确。规范写清楚后面省下的调试时间远超写规范的时间。误区二TDD 就是先写测试随便写写就行错。测试必须能验证真实行为必须能失败必须能独立运行。一个永远通过的测试等于没有测试。误区三让 AI 同时写测试和实现效率更高最危险。AI 会写出“刚好能通过自己实现”的测试而不是“验证需求”的测试。测试失去了独立验证的意义。误区四规范写完就不能改错。规范是活文档。需求变了规范就要更新。关键是先改规范再改代码而不是反过来。误区五测试覆盖率越高越好不完全对。覆盖率是手段不是目的。100% 覆盖率但测试全是无效断言不如 80% 覆盖率但测试都验证关键行为。关注关键路径覆盖和边界情况覆盖。误区六TDD 只适合单元测试错。TDD 可以用于任何层次的测试。API 开发中集成测试往往是 TDD 的主力。前端开发中组件测试和端到端测试也可以 TDD。误区七AI 生成的代码不需要审查大错。AI 生成的代码必须人工审查尤其是安全相关的逻辑。AI 可能生成看似正确但有漏洞的代码比如 SQL 拼接、权限校验缺失、敏感信息泄露等。八、工具推荐8.1 SDD 工具GitHub Spec Kit提供/speckit-constitution、/speckit-specify、/speckit-plan、/speckit-tasks、/speckit-implement等命令引导你走完整个 SDD 流程。OpenSpec轻量级 CLI 工具强调“变更即代码”工作流包括 Proposal → Spec → Design → Tasks。CodexSpec强调每一步都进行人工审查流程为 Idea → Clarify → Review → Plan → Review → Tasks → Review → Analyze → Implement。8.2 TDD 工具Pythonpytest、unittest、nose2。JavaScript/TypeScriptVitest、Jest、Mocha。JavaJUnit、TestNG。Gotesting 包、testify。集成测试Testcontainers、Fastify inject、Spring MockMvc。端到端测试Playwright、Cypress、Selenium。8.3 AI 编码助手Cursor支持自定义规则可以把规范作为上下文。Claude Code支持长上下文适合处理完整规范。GitHub Copilot支持测试生成但需要人工审查。Windsurf支持多文件编辑适合 SDD 流程。九、总结AI 时代写代码的门槛降低了但想清楚要做什么和验证做对了没有的能力反而更重要了。SDD让你在写代码之前想清楚需求、边界和验收标准。TDD让你用测试驱动实现确保每一步都可验证。AI在中间负责快速生成测试草稿和最小实现。三者结合形成一条清晰的质量链路text规范 → 计划 → 任务 → 测试 → 实现 → 重构 → 验证AI 负责提速人负责需求和质量的把关。从下一个功能开始试试先写规范再写测试最后让 AI 写实现。你会发现代码质量和工作效率可以同时提升。十、附录快速检查清单SDD 检查清单□用户故事是否从用户视角描述□验收标准是否可测试、无歧义□边界情况是否覆盖□非功能需求是否明确性能、安全、可用性□技术方案是否可行□任务是否关联验收标准□规范是否经过评审TDD 检查清单□是否先写测试再写实现□测试是否先失败且失败原因正确□实现是否最小化没有多余功能□重构后测试是否仍然通过□测试是否独立运行不依赖其他测试□测试名是否清晰描述行为□关键路径和边界情况是否覆盖□测试覆盖率是否合理AI 协作检查清单□是否让 AI 分别生成测试和实现□AI 生成的测试是否人工审查□AI 生成的实现是否人工审查□安全相关逻辑是否重点审查□是否对照规范验证实现希望这篇指南能帮助你在 AI 时代建立可靠的开发流程。规范和测试不是负担而是让你和 AI 协作更顺畅的桥梁。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑