Test-Driven Development (TDD): What It Is and How It Works

Test-driven development (TDD) is a way of building software where developers write a small automated test before the feature code. The new check fails at first because nothing has been built yet. Developers then write only the code that test requires, tidy the result, and move on to the next rule.

On the morning of December 5, 2025, one small coding mistake took down Shopify, Zoom, LinkedIn, and the websites of several banks. For roughly 25 minutes, their customers saw only error pages where checkouts, meetings, and account balances should have been. The mistake sat in Cloudflare, the company that carries and protects traffic for all of those sites. By Cloudflare’s own account, the faulty code had gone undetected for many years, because it ran only in a situation that had never occurred until that morning.

Writing the test first sounds backwards, yet it helps catch bugs in code that rarely runs. In TDD, every piece of code is written to pass a test, so even an unusual path through the program has been tried before release. However, a test exists only for the cases someone thought to check. Every test that does exist stays in the project and reruns after each change, which turns TDD into the first layer of a product’s automated testing.

Read on for the red-green-refactor cycle, the difference from behavior-driven development (BDD), how AI fits in, and the role QA plays.

What Is Test-Driven Development?

In test-driven development, the product grows in small pieces, each required to clear a check written in advance. The formal wording comes from the glossary of the International Software Testing Qualifications Board (ISTQB), which describes the method as “a software development technique in which the test cases are developed, automated and then the software is developed incrementally to pass those test cases.”

Software engineer Kent Beck popularized the practice in his 2002 book Test Driven Development: By Example. The method belongs to developers, and their tests are stored right next to the product code. Every check covers a single small piece of logic, such as how a late fee is calculated. Before starting, a developer usually writes down the cases a feature has to handle. Those notes then become tests, one at a time.

How the TDD Red Green Refactor Cycle Works

Developers often call this cycle TDD red green refactor, after the colors most test tools show. Red marks a failing test, and green marks a passing one. Picture a booking app for a hair salon with one rule: customers who cancel at least 24 hours ahead get a full refund. Building that rule takes three steps, repeated in a loop:

  • Red: The developer first writes a test that cancels a booking 48 hours before the appointment and expects the full price back. The refund feature doesn’t exist yet, so the test fails and the tool shows red. That failure proves the test can actually catch a problem.
  • Green: Next, the developer writes the bare minimum of code that makes the test pass, however crude it looks.
  • Refactor: Refactoring means improving how code is written without changing what it does. With every test passing, the developer tidies up: clearer names, no duplicated lines, and a simpler structure. The green tests then confirm that nothing broke during the cleanup.

Then the loop starts again with a second test: a cancellation three hours before the appointment, which should get no refund.

Each cycle is deliberately small, so a single feature can take dozens of them. What remains afterward is a set of unit tests: fast automated checks that each examine one piece of code. Teams often sort tests into a testing pyramid, with many fast, small ones at the bottom and a few slow runs through whole user journeys at the top. Over months, the unit tests from TDD pile up by the hundreds and form that pyramid’s wide base.

If you read code, here’s roughly how the first two steps look in Python with pytest, a popular testing tool:

# Red: written first, this test fails because refund_for() doesn't exist yet
def test_full_refund_when_cancelled_two_days_ahead():
    assert refund_for(hours_before=48, price=60) == 60

# Green: the simplest code that makes the test pass
def refund_for(hours_before, price):
    return price

The green version ignores the 24-hour rule entirely, and that’s on purpose. The three-hour cancellation test fails against this code and forces the developer to write the actual refund logic.

Why TDD Is Shift Left Testing at Its Most Literal

Shift left testing moves quality checks closer to the start of a project. As a result, problems are found soon after they’re introduced. Teams usually get there by reviewing requirements early and running automated tests on every change. Test-driven development pushes the idea as far as code allows. Each test is written before the feature it covers, so in principle no product code exists without one.

That order cuts the gap between a mistake and its discovery to a few minutes. The developer who wrote the faulty line is still looking at it, so the correction takes moments. If the mistake surfaces in a later testing round, someone has to reproduce it, trace its source, and change code that other features may already use.

TDD vs BDD: How the Two Test-First Methods Differ

BDD grew out of TDD and keeps the test-first idea, but aims its tests at a different reader. When people compare TDD vs BDD, four differences matter most:

  • Who reads the tests: Developers write TDD tests in a programming language, mainly for colleagues who also code. BDD scenarios are everyday sentences that follow a Given/When/Then pattern. Product owners and testers can review that wording without reading any code.
  • How much one test covers: A TDD test checks one small rule inside the code. A BDD scenario describes a complete behavior a user would notice, for instance: “Given a customer who forgot their password, When they ask for a reset link, Then a link arrives by email and expires after one hour.”
  • How the methods fit together: Several TDD tests sit underneath that password scenario: one creates the reset link, one enforces the one-hour limit, and one rejects any second use. Teams that combine the methods often work in two loops, starting with a BDD scenario that fails. Developers then run TDD cycles on each piece until the full behavior works.
  • What each method protects: TDD protects the code’s internal logic from mistakes. BDD keeps the people who request a feature and the developers who build it in agreement.

The deciding question is who needs to read the tests. TDD alone covers the job when only developers do. Once business people have to sign off on how features behave, BDD adds a readable layer on top.

How TDD Compares With Writing Tests After the Code

The usual alternative to TDD is test-after development, where programmers build a feature first and add tests once the code works. Both methods can end up with a similar number of tests. However, the order changes what those tests check and how the code turns out.

Test-Driven Development vs Test-After Development
Criteria
Test-driven development
Test-after development
Criteria

Timing of the tests

Test-driven development

Before each small piece of code

Test-after development

After the feature works

Criteria

Basis for the tests

Test-driven development

The rules the feature must follow

Test-after development

The code that already exists

Criteria

Risk of skipped tests

Test-driven development

Low, since no code gets written without a failing test

Test-after development

Higher, because tests are easy to drop when a deadline is close

Criteria

Effect on code structure

Test-driven development

Pushes developers toward small parts that are easy to check one at a time

Test-after development

Finished code sometimes needs rework before it can be tested

Test-driven development brings three main benefits:

  • Cleaner design: Deciding how a feature will be used before writing it produces simpler code that the next developer can follow.
  • A lasting safety net: The collected checks keep running as the product grows, so an edit that breaks old behavior fails right away.
  • Protection for risky rules: Pricing, billing, and permissions get a check for every case the developer listed.

The method also has clear costs:

  • A slower start: Writing tests up front adds time before a new feature works.
  • A poor fit for old code: Projects without tests often need restructuring just to make testing possible.
  • Blind spots on look and feel: Layout and ease of use are beyond what a small code-level check can judge.
Test-Driven Development (TDD): What It Is and How It Works
Should this feature be built test-first: four yes or no questions and a gauge from tests after to tests first

How Does AI Fit Into Test-Driven Development?

AI coding assistants and TDD work well together, as long as each side keeps its own job. The developer decides what the code must do and writes that down as tests. The assistant then produces code until all of those tests pass. Here’s how the split looks for a loyalty program where customers earn one point for every full $10 they spend:

  1. The developer writes the tests. One test expects 9 points for a $95 order, a second wants 10 for exactly $100, and a third checks that a $9 coffee earns nothing.
  2. The assistant drafts the code. Suppose its first attempt rounds $95 up to 10 points. The red test flags that mistake within seconds, and the assistant corrects it.
  3. The assistant suggests extra cases. For example, it may ask what happens to points after a refund or on an order paid with a gift card. The developer decides which of those cases belong in the rule.
  4. The developer reviews the result. That review includes confirming the original tests were left untouched.

The arrangement breaks down when the assistant writes both the tests and the code. If the tool misreads the rule, its tests will agree with its own mistake, and every check will still pass. An assistant can also turn a red test green by loosening it, for instance by deleting the $95 case. For that reason, people should write and approve the tests, even when an AI tool produces most of the code.

Where Does QA Fit Alongside TDD?

TDD tests show that code does what its developer intended. However, those tests can’t reveal whether the requirement was understood correctly, because the same person writes both the test and the code. For example, suppose a free trial should last 14 calendar days, and the developer understands that as 14 working days. The test and the code will then agree perfectly, and both will be wrong.

Strong TDD means fewer basic logic bugs reach testers. A QA team can then concentrate on the risks that sit outside a developer’s own tests:

  • Requirements before the first test: At the start of a project, QA engineers review the requirements and acceptance criteria, the checklist that decides when a feature is finished. QAwerk’s specialists also check the developers’ test list for missing cases, such as a customer who signs up twice with one email. TDD alone can’t close those gaps, since every test starts from one person’s reading of the requirement.
  • Connections between features: Integration testing checks how separate parts behave once they’re combined. A confirmed payment, for instance, should activate the customer’s subscription. A TDD test usually can’t verify that link, since it examines one piece of code in isolation.
  • Timing and real-world conditions: QA engineers test the running product the way people actually use it. Two customers might edit the same order at once, for example, while the network is slow. Unit tests rarely recreate that situation, because they run in seconds on one computer.
  • Ease of use: Exploratory testing means a tester moves through the app freely, without a script. Along the way, the specialist might notice that customers struggle to find the cancel button. No code-level check can judge that, because confusion is a human reaction.

Is TDD Right for Your Product?

With test-driven development, each new feature takes longer to build at first. In return, every rule the team defines ships with its own test, and the code stays easier to change. For a product meant to grow for years, that trade usually pays off.

Our QA engineers pick up where those tests stop, from requirements reviews before any coding starts to integration and usability checks on the finished software. That work can begin at the planning stage, or years into a mature TDD suite.

Need to enhance your testing capability? Give us a call today.

FAQ

What is test-driven development in simple terms?

Test-driven development is a programming method where developers describe the expected behavior of a feature in an automated test before writing the code for it. Work then moves in short loops. A failing test comes first (red), followed by the smallest code that makes it pass (green), and then a cleanup that keeps the test passing (refactor).

Is TDD the same as unit testing?

TDD and unit testing overlap, but they answer different questions. Unit testing describes what gets checked: individual functions and other small parts of a program, tested in isolation. TDD describes the timing: those tests come first, as a written description the code must later meet. Many teams add unit tests once the work is finished and never practice TDD.

Does TDD slow down development?

In the short term, TDD usually adds time, because developers write a test before each small part of a feature. Over a product’s life, much of that time comes back. The developer who made a mistake catches it before anyone builds on that code, and later changes break fewer existing features. The trade-off favors long-lived software over quick prototypes.

Does TDD replace QA testing?

TDD doesn’t replace QA testing, because the two look for different problems. As a developer practice, TDD confirms that each unit of code behaves as its author expected. QA testing looks at the product the way a customer would: whether the requirements were right, whether features work together, and whether the software holds up on real devices, networks, and traffic.

Can AI tools follow test-driven development?

AI coding assistants can follow a test-first loop: they read a failing test, write code, rerun the test, and repeat until it passes. As a result, tests become a practical, automatic check on AI-generated code. However, the tests themselves should come from a person who knows the business rules, since an assistant can only guess what the software is supposed to do.

See how we helped Kazidomi speed up feature delivery with test automation and become #1 startup in Belgium

Please enter your business email isn′t a business email