---
title: "What is TDD (Test-Driven Development)?"
canonical: https://wavect.io/glossary/tdd/
language: en
description: "Write the test first. Watch it fail. Write the code that makes it pass. Refactor. Repeat."
image: "https://wavect.io/img/general/bak/open_graph_preview.jpg"
---

METHODOLOGY

# TDD

Test-Driven Development

Write the test first. Watch it fail. Write the code that makes it pass. Refactor. Repeat.

Last reviewed: 2026-05-24 by [Kevin Riedl](/team/kevin-riedl/) [wiki ↗](https://www.wikidata.org/wiki/Q139796365)

Test-Driven Development is a discipline, not a methodology. The loop is: red (write a failing test), green (write the simplest code that passes), refactor (clean up without breaking the test). Done literally, it produces code with high test coverage and a forcing function against over-engineering. The discipline only pays off when those tests run on every change, which is why TDD and [CI/CD](/glossary/ci-cd/) are siblings, not separate concerns.

The reason most teams say they do TDD but actually do not: writing the test first feels slower in the moment. The compounding payoff (refactor safety, regression coverage, design pressure toward smaller units) only shows up months later. By then the team has stopped writing the tests first and convinced itself it never made a difference.

Worked example of where TDD earns its cost versus where it is theatre: a payments reconciliation module has gnarly edge cases (partial refunds, currency rounding, retries). Writing the failing test first forces you to state the expected behaviour before the code exists, and the suite catches the regression six months later when someone “simplifies” the rounding. That is TDD paying for itself. Now contrast a throwaway data-import script you will delete in two weeks: writing tests first there is pure overhead. The honest rule is to TDD the logic-heavy, expensive-to-get-wrong code and not the rest.

The most common mistake is treating coverage as a target. Chase 90% and the team writes tests for getters and setters to hit the number while skipping the integration tests where the real bugs live. Coverage is a useful diagnostic and a terrible goal; it is a metric to game. Wavect uses TDD where it pays: integration tests for anything money-shaped, contract tests for anything customer-facing, [BDD](/glossary/bdd/) -style acceptance tests where product needs to read them, unit tests for non-trivial logic. We test the hard parts well, not all parts equally, and we treat it as one practice inside a healthy [agile](/glossary/agile/) loop rather than a box to tick.

// FAQ

## FAQs

### Does TDD actually make code better?

Yes, when practised honestly: it forces smaller units, surfaces bad design early, and gives a refactor safety net. No, when bolted on for compliance: writing tests after the fact and labelling it TDD gives you the overhead without the design pressure.

### Where does TDD not pay?

Throwaway scripts, prototypes you will discard in two weeks, UI tweaks with no logic. TDD shines on logic-heavy code where regressions are expensive. For everything else, write enough tests to sleep at night, not to hit a coverage number.

### Coverage as a target: yes or no?

No. Coverage is a useful diagnostic, a terrible target. Teams that chase 90% coverage write tests for getters and setters and skip the integration tests where the real bugs live. Test the hard parts well, not all parts equally.

Related terms

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

Related services

- [Custom Software Development](/services/software-development/)

Related case studies

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

Related guides

- [The software development process, week by week](/software-development-guide/software-development-process/)

Talk to us

## 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/glossary/tdd/#term",
      "@type": "DefinedTerm",
      "alternateName": [],
      "description": "Write the test first. Watch it fail. Write the code that makes it pass. Refactor. Repeat.",
      "inDefinedTermSet": "https://wavect.io/glossary/#termset",
      "name": "TDD",
      "termCode": "tdd",
      "url": "https://wavect.io/glossary/tdd/"
    },
    {
      "@id": "https://wavect.io/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": "Write the test first. Watch it fail. Write the code that makes it pass. Refactor. Repeat.",
      "headline": "TDD",
      "inLanguage": "en",
      "isPartOf": {
        "@id": "https://wavect.io/#website",
        "@type": "WebSite"
      },
      "lastReviewed": "2026-05-24",
      "mainEntity": {
        "@id": "https://wavect.io/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/glossary/tdd/"
    },
    {
      "@type": "BreadcrumbList",
      "itemListElement": [
        {
          "@type": "ListItem",
          "item": "https://wavect.io/",
          "name": "Home",
          "position": 1
        },
        {
          "@type": "ListItem",
          "item": "https://wavect.io/glossary/",
          "name": "Tech, product & engagement glossary",
          "position": 2
        },
        {
          "@type": "ListItem",
          "item": "https://wavect.io/glossary/tdd/",
          "name": "TDD",
          "position": 3
        }
      ]
    }
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes, when practised honestly: it forces smaller units, surfaces bad design early, and gives a refactor safety net. No, when bolted on for compliance: writing tests after the fact and labelling it TDD gives you the overhead without the design pressure."
      },
      "name": "Does TDD actually make code better?"
    },
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Throwaway scripts, prototypes you will discard in two weeks, UI tweaks with no logic. TDD shines on logic-heavy code where regressions are expensive. For everything else, write enough tests to sleep at night, not to hit a coverage number."
      },
      "name": "Where does TDD not pay?"
    },
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. Coverage is a useful diagnostic, a terrible target. Teams that chase 90% coverage write tests for getters and setters and skip the integration tests where the real bugs live. Test the hard parts well, not all parts equally."
      },
      "name": "Coverage as a target: yes or no?"
    }
  ],
  "speakable": {
    "@type": "SpeakableSpecification",
    "cssSelector": [
      ".faq-question",
      ".faq-answer"
    ]
  }
}
```
