---
title: "什么是 TDD (测试驱动开发)？"
canonical: https://wavect.io/zh/glossary/tdd/
language: zh
description: "先写测试。看它失败。写让它通过的最简代码。重构。重复。"
image: "https://wavect.io/img/general/bak/open_graph_preview.jpg"
---

方法

# TDD

测试驱动开发

先写测试。看它失败。写让它通过的最简代码。重构。重复。

最近审阅: 2026-05-24 审阅人 [Kevin Riedl](/zh/team/kevin-riedl/) [wiki ↗](https://www.wikidata.org/wiki/Q139796365)

TDD 是一种纪律，不是方法论。循环是：红（写一个会失败的测试）、绿（写让它通过的最简代码）、Refactor（在不破坏测试的前提下清理）。照字面做，它产出高测试覆盖率的代码，以及一种对抗过度工程的强制力。这种纪律只有在那些测试每次变更都跑时才会有回报，所以 TDD 和 [CI/CD](/zh/glossary/ci-cd/) 是兄弟，不是分开的两件事。

多数团队嘴上做 TDD、实际却不做的原因：当下先写测试感觉更慢。复利的回报（Refactor 安全、回归覆盖、朝更小单元的设计压力）要数月之后才显现。到那时，团队早已停止先写测试，并说服自己它从没起过作用。

TDD 在哪里赚回成本、在哪里只是表演，举个实际例子：一个支付对账模块有棘手的边缘情况（部分退款、货币舍入、重试）。先写那个会失败的测试，迫使你在代码存在之前就陈述期望行为，而当六个月后有人「简化」舍入时，那套套件抓住了回归。那是 TDD 在为自己买单。再对照一个你两周后就要删掉的一次性数据导入脚本：在那里先写测试纯属开销。诚实的规则是对逻辑密集、出错代价高的代码做 TDD，其余的不做。

最常见的错误是把覆盖率当成一个目标。追 90%，团队就会为 Getter 和 Setter 写测试去凑那个数字，却跳过真正 Bug 所在的集成测试。覆盖率是一个有用的诊断、一个糟糕的目标；它是个会被刷分的指标。Wavect 在它有回报的地方用 TDD：任何和钱相关的东西做集成测试，任何面向客户的东西做契约测试，产品需要读得懂的地方做 [BDD](/zh/glossary/bdd/) 式验收测试，不平凡的逻辑做单元测试。我们把难的部分测好，而不是把所有部分平均地测，并且把它当作一个健康的 [Agile](/zh/glossary/agile/) 循环里的一项实践，而不是一个要打的勾。

// FAQ

## 常见问题

### TDD 真的能让代码变得更好吗？

诚实地实践时，能：它迫使更小的单元、让坏设计早早浮现、并给你一张 Refactor 的安全网。为了合规而硬套上去时，不能：事后补测试再贴上 TDD 的标签，只会让你拿到开销而没有设计上的压力。

### TDD 在哪里不划算？

用完即弃的脚本、两周后就要丢的原型、没有逻辑的 UI 微调。TDD 在逻辑密集、回归代价高的代码上才大放异彩。其余的，写够能让你晚上睡得着的测试，而不是为了凑一个覆盖率数字。

### 把覆盖率当目标，行不行？

不行。覆盖率是一个有用的诊断，一个糟糕的目标。追 90% 覆盖率的团队会为 Getter 和 Setter 写测试，却跳过真正藏着 Bug 的集成测试。把难的部分测好，而不是把所有部分平均地测。

相关术语

- [BDD](/zh/glossary/bdd/)
- [Agile](/zh/glossary/agile/)
- [CI/CD](/zh/glossary/ci-cd/)
- [SDLC](/zh/glossary/sdlc/)

相关服务

- [软件开发](/zh/services/software-development/)

相关案例研究

- [Polity](/zh/case-studies/polity/)

相关指南

- [软件开发流程：从首次通话到完整交接](/zh/software-development-guide/software-development-process/)

聊聊

## Structured Data

```json
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@id": "https://wavect.io/#organization",
      "@type": [
        "Organization",
        "ProfessionalService",
        "LocalBusiness"
      ],
      "employee": [
        {
          "@id": "https://wavect.io/team/kevin-riedl/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Kevin Riedl",
          "url": "https://wavect.io/team/kevin-riedl/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        },
        {
          "@id": "https://wavect.io/team/christof-jori/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Christof Jori",
          "url": "https://wavect.io/team/christof-jori/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        }
      ],
      "founder": [
        {
          "@id": "https://wavect.io/team/kevin-riedl/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Kevin Riedl",
          "url": "https://wavect.io/team/kevin-riedl/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        },
        {
          "@id": "https://wavect.io/team/christof-jori/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Christof Jori",
          "url": "https://wavect.io/team/christof-jori/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        }
      ],
      "legalRepresentative": [
        {
          "@id": "https://wavect.io/team/kevin-riedl/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Kevin Riedl",
          "url": "https://wavect.io/team/kevin-riedl/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        },
        {
          "@id": "https://wavect.io/team/christof-jori/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Christof Jori",
          "url": "https://wavect.io/team/christof-jori/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        }
      ],
      "name": "Wavect GmbH",
      "subjectOf": {
        "@id": "https://wavect.io/verified-claims.json#dataset",
        "@type": "Dataset",
        "creator": {
          "@id": "https://wavect.io/#organization",
          "@type": [
            "Organization",
            "ProfessionalService",
            "LocalBusiness"
          ]
        },
        "description": "A machine-readable registry of quantitative and qualitative claims published by Wavect, with review dates, localized page appearances and public third-party citations where available.",
        "inLanguage": "en",
        "isAccessibleForFree": true,
        "license": "https://creativecommons.org/licenses/by/4.0/",
        "name": "Wavect verified publication claims",
        "url": "https://wavect.io/verified-claims.json"
      },
      "url": "https://wavect.io/"
    },
    {
      "@id": "https://wavect.io/team/kevin-riedl/#person",
      "@type": "Person",
      "jobTitle": "Managing Director",
      "name": "Kevin Riedl",
      "sameAs": [
        "https://www.wikidata.org/wiki/Q139796365",
        "https://www.linkedin.com/in/wsdt",
        "https://github.com/wsdt"
      ],
      "url": "https://wavect.io/team/kevin-riedl/",
      "worksFor": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      }
    },
    {
      "@id": "https://wavect.io/team/christof-jori/#person",
      "@type": "Person",
      "jobTitle": "Managing Director",
      "name": "Christof Jori",
      "sameAs": [
        "https://www.wikidata.org/wiki/Q139796367",
        "https://www.linkedin.com/in/jocr77/",
        "https://github.com/jo-chris"
      ],
      "url": "https://wavect.io/team/christof-jori/",
      "worksFor": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      }
    },
    {
      "@id": "https://wavect.io/#website",
      "@type": "WebSite",
      "inLanguage": [
        "en",
        "de",
        "es",
        "zh"
      ],
      "name": "Wavect",
      "potentialAction": {
        "@type": "SearchAction",
        "query-input": "required name=search_term_string",
        "target": {
          "@type": "EntryPoint",
          "urlTemplate": "https://wavect.io/search/?q={search_term_string}"
        }
      },
      "publisher": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      },
      "url": "https://wavect.io/"
    }
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@id": "https://wavect.io/zh/glossary/tdd/#term",
      "@type": "DefinedTerm",
      "alternateName": [],
      "description": "先写测试。看它失败。写让它通过的最简代码。重构。重复。",
      "inDefinedTermSet": "https://wavect.io/zh/glossary/#termset",
      "name": "TDD",
      "termCode": "tdd",
      "url": "https://wavect.io/zh/glossary/tdd/"
    },
    {
      "@id": "https://wavect.io/zh/glossary/tdd/#webpage",
      "@type": "WebPage",
      "about": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      },
      "author": {
        "@id": "https://wavect.io/team/kevin-riedl/#person",
        "@type": "Person",
        "name": "Kevin Riedl",
        "url": "https://wavect.io/team/kevin-riedl/"
      },
      "dateModified": "2026-05-24",
      "description": "先写测试。看它失败。写让它通过的最简代码。重构。重复。",
      "headline": "TDD",
      "inLanguage": "zh",
      "isPartOf": {
        "@id": "https://wavect.io/#website",
        "@type": "WebSite"
      },
      "lastReviewed": "2026-05-24",
      "mainEntity": {
        "@id": "https://wavect.io/zh/glossary/tdd/#term"
      },
      "mentions": [
        {
          "@id": "https://wavect.io/#organization",
          "@type": [
            "Organization",
            "ProfessionalService",
            "LocalBusiness"
          ]
        }
      ],
      "name": "TDD",
      "reviewedBy": {
        "@id": "https://wavect.io/team/christof-jori/#person",
        "@type": "Person",
        "name": "Christof Jori",
        "url": "https://wavect.io/team/christof-jori/"
      },
      "speakable": {
        "@type": "SpeakableSpecification",
        "cssSelector": [
          ".gls-single__h1",
          ".gls-single__tldr"
        ]
      },
      "url": "https://wavect.io/zh/glossary/tdd/"
    },
    {
      "@type": "BreadcrumbList",
      "itemListElement": [
        {
          "@type": "ListItem",
          "item": "https://wavect.io/zh/",
          "name": "首页",
          "position": 1
        },
        {
          "@type": "ListItem",
          "item": "https://wavect.io/zh/glossary/",
          "name": "技术、产品与合作模式术语表",
          "position": 2
        },
        {
          "@type": "ListItem",
          "item": "https://wavect.io/zh/glossary/tdd/",
          "name": "TDD",
          "position": 3
        }
      ]
    }
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "诚实地实践时，能：它迫使更小的单元、让坏设计早早浮现、并给你一张 Refactor 的安全网。为了合规而硬套上去时，不能：事后补测试再贴上 TDD 的标签，只会让你拿到开销而没有设计上的压力。"
      },
      "name": "TDD 真的能让代码变得更好吗？"
    },
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "用完即弃的脚本、两周后就要丢的原型、没有逻辑的 UI 微调。TDD 在逻辑密集、回归代价高的代码上才大放异彩。其余的，写够能让你晚上睡得着的测试，而不是为了凑一个覆盖率数字。"
      },
      "name": "TDD 在哪里不划算？"
    },
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "不行。覆盖率是一个有用的诊断，一个糟糕的目标。追 90% 覆盖率的团队会为 Getter 和 Setter 写测试，却跳过真正藏着 Bug 的集成测试。把难的部分测好，而不是把所有部分平均地测。"
      },
      "name": "把覆盖率当目标，行不行？"
    }
  ],
  "speakable": {
    "@type": "SpeakableSpecification",
    "cssSelector": [
      ".faq-question",
      ".faq-answer"
    ]
  }
}
```
