DMF_Crawler/docs/research/_raw/tdd-red/gds-way-test-driven-development.raw.html
Yun Chan 56a6e2da93 chore: 저장소 구조 정리 및 문서화, 첫 커밋
- src/dist 산출물 분리 원칙 정리(.gitignore, .gitattributes)
- 루트 및 주요 폴더(config/scripts/prompts/tests/src, 런타임 폴더 5종)에
  안내용 README.md 추가
- CHANGELOG.md, LICENSE, docs/ops/05-release-and-versioning.md 추가
- docs/README.md 문서 지도 갱신
2026-09-04 09:25:44 +09:00

290 lines
31 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" class="govuk-template no-js">
<head>
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Test-driven development (TDD) - The GDS Way</title>
<link href="/stylesheets/manifest.css" rel="stylesheet" />
<link rel="canonical" href="https://gds-way.digital.cabinet-office.gov.uk/standards/test-driven-development.html">
<link rel="icon" sizes="48x48" href="/images/favicon.ico">
<link rel="icon" sizes="any" href="/images/favicon.svg" type="image/svg+xml">
<meta name="twitter:card" content="summary" />
<meta name="twitter:domain" content="gds-way.digital.cabinet-office.gov.uk" />
<meta name="twitter:image" content="https://gds-way.digital.cabinet-office.gov.uk/images/opengraph-image.png" />
<meta name="twitter:title" content="Test-driven development (TDD) - The GDS Way" />
<meta name="twitter:url" content="https://gds-way.digital.cabinet-office.gov.uk/standards/test-driven-development.html" />
<meta property="og:image" content="https://gds-way.digital.cabinet-office.gov.uk/images/opengraph-image.png" />
<meta property="og:site_name" content="The GDS Way" />
<meta property="og:title" content="Test-driven development (TDD)" />
<meta property="og:type" content="object" />
<meta property="og:url" content="https://gds-way.digital.cabinet-office.gov.uk/standards/test-driven-development.html" />
</head>
<body class="govuk-template__body">
<script>document.body.className += ' js-enabled' + ('noModule' in HTMLScriptElement.prototype ? ' govuk-frontend-supported' : '');</script>
<header class="govuk-template__header app-header" role="banner" data-module="govuk-header">
<div class="govuk-header app-header" role="banner" data-module="govuk-header">
<div class="govuk-header__container govuk-header__container--full-width">
<div class="govuk-header__logo">
<a href="/" class="govuk-header__link govuk-header__homepage-link">
<span class="govuk-header__product-name">
The GDS Way
</span>
</a>
</div>
</div>
</div>
</header>
<div class="govuk-service-navigation app-pane__navigation" data-module="govuk-service-navigation">
<div class="govuk-width-container">
<div class="govuk-service-navigation__container">
<nav aria-label="Menu" class="govuk-service-navigation__wrapper">
<button type="button" class="govuk-service-navigation__toggle govuk-js-service-navigation-toggle" aria-controls="navigation" hidden aria-hidden="true">
Menu
</button>
<ul class="govuk-service-navigation__list" id="navigation">
<li class="govuk-service-navigation__item ">
<a class="govuk-service-navigation__link" href="https://github.com/alphagov/gds-way">
GitHub
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="app-pane__header toc-open-disabled">
<a href="#content" class="govuk-skip-link" data-module="govuk-skip-link">Skip to main content</a>
</div>
<div id="toc-heading" class="toc-show fixedsticky">
<button type="button" class="toc-show__label js-toc-show" aria-controls="toc">
Table of contents <span class="toc-show__icon"></span>
</button>
</div>
<div class="app-pane__body" data-module="in-page-navigation">
<div class="app-pane__toc">
<div class="toc" data-module="table-of-contents" tabindex="-1">
<div class="search" data-module="search" data-path-to-site-root="/">
<form action="https://www.google.co.uk/search" method="get" role="search" class="search__form govuk-!-margin-bottom-4">
<input type="hidden" name="as_sitesearch" value="https://gds-way.digital.cabinet-office.gov.uk"/>
<label class="govuk-label search__label" for="search">
Search (via Google)
</label>
<input
type="search"
id="search" name="q"
class="govuk-input govuk-!-margin-bottom-0 search__input"
aria-controls="search-results"
placeholder="Search">
<button type="submit" class="search__button">Search</button>
</form>
</div>
<button type="button" class="toc__close js-toc-close" aria-controls="toc" aria-label="Hide table of contents"></button>
<nav id="toc" class="js-toc-list toc__list" aria-labelledby="toc-heading">
<ul>
<li>
<a href="#test-driven-development-tdd"><span>Test-driven development (TDD)</span></a>
<ul>
<li>
<a href="#red-green-refactor"><span>RedGreenRefactor</span></a>
<ul>
<li>
<a href="#red-write-a-failing-test"><span>Red - write a failing test</span></a>
</li>
<li>
<a href="#green-make-all-tests-pass"><span>Green - make all tests pass</span></a>
</li>
<li>
<a href="#refactor-iterate-on-your-design"><span>Refactor - iterate on your design</span></a>
</li>
</ul>
</li>
<li>
<a href="#why-we-recommend-it"><span>Why we recommend it</span></a>
</li>
<li>
<a href="#what-if-we-can-39-t-do-tdd"><span>What if we cant do TDD?</span></a>
</li>
<li>
<a href="#beyond-tdd"><span>Beyond TDD</span></a>
</li>
<li>
<a href="#useful-resources"><span>Useful resources</span></a>
<ul>
<li>
<a href="#getting-started"><span>Getting started</span></a>
</li>
<li>
<a href="#getting-better"><span>Getting better</span></a>
</li>
<li>
<a href="#books-and-blogposts"><span>Books and blogposts</span></a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</div>
</div>
<div class="app-pane__content toc-open-disabled" aria-label="Content">
<main id="content" class="govuk-main-wrapper technical-documentation" data-module="anchored-headings">
<div class="page-banner">
<p><strong>The GDS Way and its content is intended for internal use by the GDS Digital Products community.</strong></p>
</div>
<h1 id="test-driven-development-tdd">Test-driven development (TDD)</h1>
<p>GDS advocates for agile software development practices because we believe that flexibility and responsiveness-to-change are key to building software that meets the needs of our users.</p>
<p>Test-driven development (TDD) is a core agile software development practice which aims to build flexibility and correctness into production software.</p>
<p>The process starts with a set of desired behaviours for a piece of code. This list could include happy-path behaviours, error cases, and interaction points with other components.</p>
<h2 id="red-green-refactor">RedGreenRefactor</h2>
<p>The inner-loop of TDD is also commonly referred to as &ldquo;Red-Green-Refactor&rdquo;; red to represent a failing test, green to represent all passing tests, and refactoring only when all tests are passing.</p>
<p><svg version="1.1" viewBox="0.0 0.0 518.488188976378 375.79527559055117" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="500px" style="display: block; margin: 0 auto"><clipPath id="p.0"><path d="m0 0l518.48816 0l0 375.7953l-518.48816 0l0 -375.7953z" clip-rule="nonzero"/></clipPath><g clip-path="url(#p.0)"><path fill="#000000" fill-opacity="0.0" d="m0 0l518.48816 0l0 375.7953l-518.48816 0z" fill-rule="evenodd"/><path fill="#ff0000" d="m5.7244096 82.03018l0 0c0 -38.381615 31.114447 -69.49606 69.49606 -69.49606l0 0c18.431503 0 36.108093 7.321886 49.141136 20.354925c13.033043 13.033039 20.354927 30.709637 20.354927 49.141136l0 0c0 38.381615 -31.114449 69.49606 -69.49606 69.49606l0 0c-38.38162 0 -69.49606 -31.114449 -69.49606 -69.49606z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m5.7244096 82.03018l0 0c0 -38.381615 31.114447 -69.49606 69.49606 -69.49606l0 0c18.431503 0 36.108093 7.321886 49.141136 20.354925c13.033043 13.033039 20.354927 30.709637 20.354927 49.141136l0 0c0 38.381615 -31.114449 69.49606 -69.49606 69.49606l0 0c-38.38162 0 -69.49606 -31.114449 -69.49606 -69.49606z" fill-rule="evenodd"/><path fill="#ff0000" d="m58.10828 71.03018l34.224384 0l0 22.400002l-34.224384 0l0 -22.400002z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m58.10828 72.06117l34.224384 0l0 21.452866l-34.224384 0l0 -21.452866z" fill-rule="nonzero"/><path fill="#000000" d="m59.57703 88.95018l0 -13.359375l5.921879 0q1.78125 0 2.703125 0.359375q0.9375 0.359375 1.484375 1.28125q0.5625 0.90625 0.5625 2.015625q0 1.40625 -0.921875 2.390625q-0.921875 0.96875 -2.84375 1.234375q0.703125 0.34375 1.078125 0.671875q0.765625 0.703125 1.453125 1.765625l2.328125 3.640625l-2.21875 0l-1.765625 -2.78125q-0.78125 -1.203125 -1.28125 -1.828125q-0.5 -0.640625 -0.90625 -0.890625q-0.390625 -0.265625 -0.796875 -0.359375q-0.296875 -0.078125 -0.9843788 -0.078125l-2.046875 0l0 5.9375l-1.765625 0zm1.765625 -7.453125l3.7968788 0q1.21875 0 1.890625 -0.25q0.6875 -0.265625 1.046875 -0.8125q0.359375 -0.546875 0.359375 -1.1875q0 -0.953125 -0.6875 -1.5625q-0.6875 -0.609375 -2.1875 -0.609375l-4.218754 0l0 4.421875zm18.09795 4.34375l1.6875 0.203125q-0.40625 1.484375 -1.484375 2.3125q-1.078125 0.8125 -2.765625 0.8125q-2.125 0 -3.375 -1.296875q-1.234375 -1.3125 -1.234375 -3.671875q0 -2.453125 1.25 -3.796875q1.265625 -1.34375 3.265625 -1.34375q1.9375 0 3.15625 1.328125q1.234375 1.3125 1.234375 3.703125q0 0.15625 0 0.4375l-7.21875 0q0.09375 1.59375 0.90625 2.453125q0.8125 0.84375 2.015625 0.84375q0.90625 0 1.546875 -0.46875q0.640625 -0.484375 1.015625 -1.515625zm-5.390625 -2.65625l5.40625 0q-0.109375 -1.21875 -0.625 -1.828125q-0.78125 -0.953125 -2.03125 -0.953125q-1.125 0 -1.90625 0.765625q-0.765625 0.75 -0.84375 2.015625zm15.406967 5.765625l0 -1.21875q-0.90625 1.4375 -2.703125 1.4375q-1.15625 0 -2.125 -0.640625q-0.96875 -0.640625 -1.5 -1.78125q-0.53125 -1.140625 -0.53125 -2.625q0 -1.453125 0.484375 -2.625q0.484375 -1.1875 1.4375 -1.8125q0.96875 -0.625 2.171875 -0.625q0.875 0 1.546875 0.375q0.6875 0.359375 1.109375 0.953125l0 -4.796875l1.640625 0l0 13.359375l-1.53125 0zm-5.171875 -4.828125q0 1.859375 0.78125 2.78125q0.78125 0.921875 1.84375 0.921875q1.078125 0 1.828125 -0.875q0.75 -0.890625 0.75 -2.6875q0 -1.984375 -0.765625 -2.90625q-0.765625 -0.9375 -1.890625 -0.9375q-1.078125 0 -1.8125 0.890625q-0.734375 0.890625 -0.734375 2.8125z" fill-rule="nonzero"/><path fill="#010000" fill-opacity="0.0" d="m92.332664 72.06117l0 0l0 21.452866l0 0l0 -21.452866z" fill-rule="nonzero"/><path fill="#00ff00" d="m373.77292 82.03018l0 0c0 -38.381615 31.11444 -69.49606 69.49606 -69.49606l0 0c18.431488 0 36.108093 7.321886 49.141144 20.354925c13.03302 13.033039 20.354889 30.709637 20.354889 49.141136l0 0c0 38.381615 -31.11441 69.49606 -69.49603 69.49606l0 0c-38.381622 0 -69.49606 -31.114449 -69.49606 -69.49606z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m373.77292 82.03018l0 0c0 -38.381615 31.11444 -69.49606 69.49606 -69.49606l0 0c18.431488 0 36.108093 7.321886 49.141144 20.354925c13.03302 13.033039 20.354889 30.709637 20.354889 49.141136l0 0c0 38.381615 -31.11441 69.49606 -69.49603 69.49606l0 0c-38.381622 0 -69.49606 -31.114449 -69.49606 -69.49606z" fill-rule="evenodd"/><path fill="#000000" d="m425.03085 83.715805l0 -1.578125l5.65625 0l0 4.953125q-1.296875 1.046875 -2.6875 1.578125q-1.375 0.515625 -2.84375 0.515625q-1.96875 0 -3.578125 -0.84375q-1.609375 -0.84375 -2.421875 -2.4375q-0.8125 -1.59375 -0.8125 -3.5625q0 -1.953125 0.8125 -3.640625q0.8125 -1.6875 2.34375 -2.5q1.53125 -0.828125 3.515625 -0.828125q1.453125 0 2.625 0.46875q1.171875 0.46875 1.828125 1.3125q0.671875 0.828125 1.015625 2.171875l-1.59375 0.4375q-0.296875 -1.015625 -0.75 -1.59375q-0.4375 -0.59375 -1.265625 -0.9375q-0.828125 -0.34375 -1.84375 -0.34375q-1.203125 0 -2.09375 0.375q-0.890625 0.359375 -1.4375 0.96875q-0.53125 0.59375 -0.828125 1.3125q-0.515625 1.234375 -0.515625 2.6875q0 1.78125 0.609375 2.984375q0.625 1.203125 1.796875 1.796875q1.171875 0.578125 2.5 0.578125q1.140625 0 2.234375 -0.4375q1.09375 -0.453125 1.65625 -0.953125l0 -2.484375l-3.921875 0zm8.042664 5.234375l0 -9.671875l1.46875 0l0 1.46875q0.5625 -1.03125 1.03125 -1.359375q0.484375 -0.328125 1.0625 -0.328125q0.828125 0 1.6875 0.53125l-0.5625 1.515625q-0.609375 -0.359375 -1.203125 -0.359375q-0.546875 0 -0.96875 0.328125q-0.421875 0.328125 -0.609375 0.890625q-0.28125 0.875 -0.28125 1.921875l0 5.0625l-1.625 0zm12.853302 -3.109375l1.6875 0.203125q-0.40625 1.484375 -1.484375 2.3125q-1.078125 0.8125 -2.765625 0.8125q-2.125 0 -3.375 -1.296875q-1.234375 -1.3125 -1.234375 -3.671875q0 -2.453125 1.25 -3.796875q1.265625 -1.34375 3.265625 -1.34375q1.9375 0 3.15625 1.328125q1.234375 1.3125 1.234375 3.703125q0 0.15625 0 0.4375l-7.21875 0q0.09375 1.59375 0.90625 2.453125q0.8125 0.84375 2.015625 0.84375q0.90625 0 1.546875 -0.46875q0.640625 -0.484375 1.015625 -1.515625zm-5.390625 -2.65625l5.40625 0q-0.109375 -1.21875 -0.625 -1.828125q-0.78125 -0.953125 -2.03125 -0.953125q-1.125 0 -1.90625 0.765625q-0.765625 0.75 -0.84375 2.015625zm15.766357 2.65625l1.6875 0.203125q-0.40625 1.484375 -1.484375 2.3125q-1.078125 0.8125 -2.765625 0.8125q-2.125 0 -3.375 -1.296875q-1.234375 -1.3125 -1.234375 -3.671875q0 -2.453125 1.25 -3.796875q1.265625 -1.34375 3.265625 -1.34375q1.9375 0 3.15625 1.328125q1.234375 1.3125 1.234375 3.703125q0 0.15625 0 0.4375l-7.21875 0q0.09375 1.59375 0.90625 2.453125q0.8125 0.84375 2.015625 0.84375q0.90625 0 1.546875 -0.46875q0.640625 -0.484375 1.015625 -1.515625zm-5.390625 -2.65625l5.40625 0q-0.109375 -1.21875 -0.625 -1.828125q-0.78125 -0.953125 -2.03125 -0.953125q-1.125 0 -1.90625 0.765625q-0.765625 0.75 -0.84375 2.015625zm9.141327 5.765625l0 -9.671875l1.46875 0l0 1.375q1.0625 -1.59375 3.078125 -1.59375q0.875 0 1.609375 0.3125q0.734375 0.3125 1.09375 0.828125q0.375 0.5 0.515625 1.203125q0.09375 0.453125 0.09375 1.59375l0 5.953125l-1.640625 0l0 -5.890625q0 -1.0 -0.203125 -1.484375q-0.1875 -0.5 -0.671875 -0.796875q-0.484375 -0.296875 -1.140625 -0.296875q-1.046875 0 -1.8125 0.671875q-0.75 0.65625 -0.75 2.515625l0 5.28125l-1.640625 0z" fill-rule="nonzero"/><path fill="#4a86e8" d="m189.74866 293.76605l0 0c0 -38.381607 31.114456 -69.49606 69.49606 -69.49606l0 0c18.431519 0 36.108093 7.321884 49.141144 20.354935c13.033051 13.033035 20.35492 30.70964 20.35492 49.14113l0 0c0 38.381622 -31.11444 69.49606 -69.49606 69.49606l0 0c-38.381607 0 -69.49606 -31.11444 -69.49606 -69.49606z" fill-rule="evenodd"/><path stroke="#000000" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m189.74866 293.76605l0 0c0 -38.381607 31.114456 -69.49606 69.49606 -69.49606l0 0c18.431519 0 36.108093 7.321884 49.141144 20.354935c13.033051 13.033035 20.35492 30.70964 20.35492 49.14113l0 0c0 38.381622 -31.11444 69.49606 -69.49606 69.49606l0 0c-38.381607 0 -69.49606 -31.11444 -69.49606 -69.49606z" fill-rule="evenodd"/><path fill="#000000" d="m225.45972 300.68607l0 -13.359375l5.921875 0q1.78125 0 2.703125 0.359375q0.9375 0.359375 1.484375 1.28125q0.5625 0.90625 0.5625 2.015625q0 1.40625 -0.921875 2.390625q-0.921875 0.96875 -2.84375 1.234375q0.703125 0.34375 1.078125 0.671875q0.765625 0.703125 1.453125 1.765625l2.328125 3.640625l-2.21875 0l-1.765625 -2.78125q-0.78125 -1.203125 -1.28125 -1.828125q-0.5 -0.640625 -0.90625 -0.890625q-0.390625 -0.265625 -0.796875 -0.359375q-0.296875 -0.078125 -0.984375 -0.078125l-2.046875 0l0 5.9375l-1.765625 0zm1.765625 -7.453125l3.796875 0q1.21875 0 1.890625 -0.25q0.6875 -0.265625 1.046875 -0.8125q0.359375 -0.546875 0.359375 -1.1875q0 -0.953125 -0.6875 -1.5625q-0.6875 -0.609375 -2.1875 -0.609375l-4.21875 0l0 4.421875zm18.097946 4.34375l1.6875 0.203125q-0.40625 1.484375 -1.484375 2.3125q-1.078125 0.8125 -2.765625 0.8125q-2.125 0 -3.375 -1.296875q-1.234375 -1.3125 -1.234375 -3.671875q0 -2.453125 1.25 -3.796875q1.265625 -1.34375 3.265625 -1.34375q1.9375 0 3.15625 1.328125q1.234375 1.3125 1.234375 3.703125q0 0.15625 0 0.4375l-7.21875 0q0.09375 1.59375 0.90625 2.453125q0.8125 0.84375 2.015625 0.84375q0.90625 0 1.546875 -0.46875q0.640625 -0.484375 1.015625 -1.515625zm-5.390625 -2.65625l5.40625 0q-0.109375 -1.21875 -0.625 -1.828125q-0.78125 -0.953125 -2.03125 -0.953125q-1.125 0 -1.90625 0.765625q-0.765625 0.75 -0.84375 2.015625zm9.531967 5.765625l0 -8.40625l-1.453125 0l0 -1.265625l1.453125 0l0 -1.03125q0 -0.96875 0.171875 -1.453125q0.234375 -0.640625 0.828125 -1.03125q0.59375 -0.390625 1.671875 -0.390625q0.6875 0 1.53125 0.15625l-0.25 1.4375q-0.5 -0.09375 -0.953125 -0.09375q-0.75 0 -1.0625 0.328125q-0.3125 0.3125 -0.3125 1.1875l0 0.890625l1.890625 0l0 1.265625l-1.890625 0l0 8.40625l-1.625 0zm11.105194 -1.1875q-0.921875 0.765625 -1.765625 1.09375q-0.828125 0.3125 -1.796875 0.3125q-1.5937653 0 -2.4531403 -0.78125q-0.859375 -0.78125 -0.859375 -1.984375q0 -0.71875 0.328125 -1.296875q0.328125 -0.59375 0.84375 -0.9375q0.53125 -0.359375 1.1875153 -0.546875q0.46875 -0.125 1.453125 -0.25q1.984375 -0.234375 2.921875 -0.5625q0.015625 -0.34375 0.015625 -0.421875q0 -1.0 -0.46875 -1.421875q-0.625 -0.546875 -1.875 -0.546875q-1.15625 0 -1.703125 0.40625q-0.54689026 0.40625 -0.81251526 1.421875l-1.609375 -0.21875q0.21875 -1.015625 0.71875 -1.640625q0.5 -0.640625 1.4531403 -0.984375q0.953125 -0.34375 2.1875 -0.34375q1.25 0 2.015625 0.296875q0.78125 0.28125 1.140625 0.734375q0.375 0.4375 0.515625 1.109375q0.078125 0.421875 0.078125 1.515625l0 2.1875q0 2.28125 0.109375 2.890625q0.109375 0.59375 0.40625 1.15625l-1.703125 0q-0.265625 -0.515625 -0.328125 -1.1875zm-0.140625 -3.671875q-0.890625 0.375 -2.671875 0.625q-1.015625 0.140625 -1.4375 0.328125q-0.42189026 0.1875 -0.65626526 0.53125q-0.21875 0.34375 -0.21875 0.78125q0 0.65625 0.5 1.09375q0.50001526 0.4375 1.4531403 0.4375q0.9375 0 1.671875 -0.40625q0.75 -0.421875 1.09375 -1.140625q0.265625 -0.5625 0.265625 -1.640625l0 -0.609375zm10.516327 1.3125l1.609375 0.21875q-0.265625 1.65625 -1.359375 2.609375q-1.078125 0.9375 -2.671875 0.9375q-1.984375 0 -3.1875 -1.296875q-1.203125 -1.296875 -1.203125 -3.71875q0 -1.578125 0.515625 -2.75q0.515625 -1.171875 1.578125 -1.75q1.0625 -0.59375 2.3125 -0.59375q1.578125 0 2.578125 0.796875q1.0 0.796875 1.28125 2.265625l-1.59375 0.234375q-0.234375 -0.96875 -0.8125 -1.453125q-0.578125 -0.5 -1.390625 -0.5q-1.234375 0 -2.015625 0.890625q-0.78125 0.890625 -0.78125 2.8125q0 1.953125 0.75 2.84375q0.75 0.875 1.953125 0.875q0.96875 0 1.609375 -0.59375q0.65625 -0.59375 0.828125 -1.828125zm6.59375 2.078125l0.234375 1.453125q-0.6875 0.140625 -1.234375 0.140625q-0.890625 0 -1.390625 -0.28125q-0.484375 -0.28125 -0.6875 -0.734375q-0.203125 -0.46875 -0.203125 -1.9375l0 -5.578125l-1.203125 0l0 -1.265625l1.203125 0l0 -2.390625l1.625 -0.984375l0 3.375l1.65625 0l0 1.265625l-1.65625 0l0 5.671875q0 0.6875 0.078125 0.890625q0.09375 0.203125 0.28125 0.328125q0.203125 0.109375 0.578125 0.109375q0.265625 0 0.71875 -0.0625zm0.9958191 -3.375q0 -2.6875 1.484375 -3.96875q1.25 -1.078125 3.046875 -1.078125q2.0 0 3.265625 1.3125q1.265625 1.296875 1.265625 3.609375q0 1.859375 -0.5625 2.9375q-0.5625 1.0625 -1.640625 1.65625q-1.0625 0.59375 -2.328125 0.59375q-2.03125 0 -3.28125 -1.296875q-1.25 -1.3125 -1.25 -3.765625zm1.6875 0q0 1.859375 0.796875 2.796875q0.8125 0.921875 2.046875 0.921875q1.21875 0 2.03125 -0.921875q0.8125 -0.9375 0.8125 -2.84375q0 -1.796875 -0.8125 -2.71875q-0.8125 -0.921875 -2.03125 -0.921875q-1.234375 0 -2.046875 0.921875q-0.796875 0.90625 -0.796875 2.765625zm9.281952 4.84375l0 -9.671875l1.46875 0l0 1.46875q0.5625 -1.03125 1.03125 -1.359375q0.484375 -0.328125 1.0625 -0.328125q0.828125 0 1.6875 0.53125l-0.5625 1.515625q-0.609375 -0.359375 -1.203125 -0.359375q-0.546875 0 -0.96875 0.328125q-0.421875 0.328125 -0.609375 0.890625q-0.28125 0.875 -0.28125 1.921875l0 5.0625l-1.625 0z" fill-rule="nonzero"/><path fill="#000000" fill-opacity="0.0" d="m144.71654 82.03018l229.07088 0" fill-rule="evenodd"/><path stroke="#000000" stroke-width="4.0" stroke-linejoin="round" stroke-linecap="butt" d="m144.71654 82.03018l205.07088 0" fill-rule="evenodd"/><path fill="#000000" stroke="#000000" stroke-width="4.0" stroke-linecap="butt" d="m349.7874 88.637115l18.152374 -6.6069336l-18.152374 -6.606926z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m308.38586 244.62492l85.73227 -113.44882" fill-rule="evenodd"/><path stroke="#000000" stroke-width="4.0" stroke-linejoin="round" stroke-linecap="butt" d="m322.85553 225.47736l56.79297 -75.15369" fill-rule="evenodd"/><path fill="#000000" stroke="#000000" stroke-width="4.0" stroke-linecap="butt" d="m317.5844 221.49402l-5.673004 18.465591l16.21521 -10.498932z" fill-rule="evenodd"/><path fill="#000000" stroke="#000000" stroke-width="4.0" stroke-linecap="butt" d="m384.91962 154.30699l5.673004 -18.465576l-16.21524 10.498917z" fill-rule="evenodd"/><path fill="#000000" fill-opacity="0.0" d="m210.10359 244.62492l-85.73229 -113.44882" fill-rule="evenodd"/><path stroke="#000000" stroke-width="4.0" stroke-linejoin="round" stroke-linecap="butt" d="m210.10359 244.62492l-71.262634 -94.301254" fill-rule="evenodd"/><path fill="#000000" stroke="#000000" stroke-width="4.0" stroke-linecap="butt" d="m144.11206 146.34033l-16.215225 -10.498917l5.673004 18.465576z" fill-rule="evenodd"/></g></svg></p>
<h3 id="red-write-a-failing-test">Red - write a failing test</h3>
<p>Turn exactly one item on the list into an actual, concrete, runnable test. This test should fail when you run it, and it should fail in the way you expect.</p>
<p>If it fails unexpectedly, that could indicate a functionality gap or a misimplementation. For example, setting a field as immutable when you expect to mutate it on later interactions.</p>
<h3 id="green-make-all-tests-pass">Green - make all tests pass</h3>
<p>Change the code to make all tests, including the new test, pass. If you discover that you are missing a behaviour or test, add it to the list.</p>
<p>Tests should pass in a timely manner and slow-running tests should be investigated in the refactoring stage. You may choose to reduce the size of your test case or decompose the functionality into multiple, separately testable, components.</p>
<h3 id="refactor-iterate-on-your-design">Refactor - iterate on your design</h3>
<p>Improve the design and implementation of the code by removing duplication, utilising well known patterns and structures.</p>
<p>This is where the majority of software design happens. You have code that behaves as specified in the tests and that is your safety net for iterating the models and structures of the code to best represent the software&rsquo;s needs at that particular time.</p>
<p>You should also let yourself be guided by the tests you&rsquo;ve written; if a test is hard to write or you find yourself having to update many tests to support a new test without using automated refactoring tools, then take a step back examine why.</p>
<p>These steps are repeated until your set of behaviours is exhausted.</p>
<h2 id="why-we-recommend-it">Why we recommend it</h2>
<p>The advantage of writing the tests before the implementation is that the behaviour of the code you will write is defined first, rather than implementing the change and retroactively applying tests.</p>
<p>A test-first approach gives you quick feedback on the design of your code - if your code is becoming difficult to test or has many dependencies, these are signals that you likely need to refactor.</p>
<blockquote>
<p>For each desired change, make the change easy (warning: this may be hard), then make the easy change - Kent Beck</p>
</blockquote>
<p>TDD naturally lends itself to our recommended approach to <a href="/standards/breaking-down-work.html">breaking down work</a>. If you are careful about introducing feature toggles so that code can be &ldquo;dark launched&rdquo; into production environments, TDD can give you a robust and reliable iterative workflow.</p>
<p>For example, if you are defining a new component, you could first define the interface, integrate a &ldquo;do nothing&rdquo; or noop version of that component into the live codebase, and then iterate on that implementation or another implementation safely.</p>
<p>TDD is also a great tool for cultivating a testing mindset in teams. Practicing these techniques and concepts will teach how to approach a problem with the curiosity (what does this code do if I give it these inputs?) and skepticism (does this code really do what it&rsquo;s supposed to?) necessary for building robust and resilient user-facing software.</p>
<h2 id="what-if-we-can-39-t-do-tdd">What if we can&rsquo;t do TDD?</h2>
<p>The most valuable output of the TDD process is not the code itself but the tight feedback loops that allow you to reflect and the iterative design decisions that you make along the way.</p>
<p>If doing what Kent Beck calls <a href="https://tidyfirst.substack.com/p/canon-tdd">canon TDD</a> is not possible, for whatever reason, that&rsquo;s okay as long as you have another mechanism for realising the fast feedback and incremental delivery advantages that TDD does provide.</p>
<h2 id="beyond-tdd">Beyond TDD</h2>
<p>TDD works best when the feedback loops are fast. For unit testing, which should be subsecond, and component integration testing, the TDD process is very effective.</p>
<p>However, it is less effective for testing processes with longer feedback loops such as feature acceptance testing across multiple components, especially if you are unable to run those tests locally before pushing your code.</p>
<p>As systems get more complex, we usually cannot enumerate and emulate all possible interactions within unit and integration tests. Exploratory testing, done collaboratively and built on a solid foundation of fast tests, can help a team tease out unknown or unexpected behaviours of their system.</p>
<h2 id="useful-resources">Useful resources</h2>
<h3 id="getting-started">Getting started</h3>
<p>If you&rsquo;re struggling to write your first test, consider the approach of <a href="https://www.agilealliance.org/resources/sessions/test-driven-development-guided-by-zombies/">Zero-One-Many</a>: start with the empty case, then consider the singular case, then generalise to many kinds of inputs.</p>
<p>For example, if you were processing some kind of file input, handle the empty case first (what if the file has no lines?), then the singular case (what if the file has a single line?), and then generalise.</p>
<h3 id="getting-better">Getting better</h3>
<p>TDD is a skill like any other, and one which you can develop your fluency with through practice.</p>
<p>Try working through some example problems while adding a constraint such as <a href="https://github.com/sf105/tdd-as-if-you-meant-it">TDD-As-If-You-Meant-It</a>, where you can only write code in your test package, and any production code must be refactored out rather than written directly. This constraint reframes the TDD approach by forcing you to write tests first rather than retrofitting them onto the existing production code.</p>
<p>You could also look at GeePaw Hill&rsquo;s <a href="https://www.geepawhill.org/2021/10/26/mmmss-a-closer-look-at-steps/">Many More Much Smaller Steps</a>, which advocates for framing work as a composition of a lot of smaller, and therefore safer, changes than a few large, and therefore risky, changes.</p>
<h3 id="books-and-blogposts">Books and blogposts</h3>
<ul>
<li><a href="https://www.oreilly.com/library/view/growing-object-oriented-software/9780321574442/">Growing Object-Oriented Software, Guided By Tests</a> - Nat Pryce &amp; Steve Freeman</li>
<li><a href="https://www.oreilly.com/library/view/test-driven-development/0321146530/">Test-Driven Development By Example</a> - Kent Beck</li>
<li><a href="https://codemanship.co.uk/papers.html">TDD</a> - Jason Gorman</li>
</ul>
<div data-module='page-expiry' data-last-reviewed-on="2027-08-20">
<div class='page-expiry--not-expired'>
This page was last reviewed on 20 August 2026.
It needs to be reviewed again on 20 August 2027
by the page owner <a href="https://gds.slack.com/messages/gds-way">#gds-way</a>
.
</div>
<div class='page-expiry--expired' hidden>
This page was set to be reviewed before 20 August 2027
by the page owner <a href="https://gds.slack.com/messages/gds-way">#gds-way</a>.
This might mean the content is out of date.
</div>
</div>
</main>
<aside>
<ul class="contribution-banner">
<li><a href="https://github.com/alphagov/gds-way/blob/main/source/standards/test-driven-development.html.md.erb">View source</a></li>
<li><a href="https://github.com/alphagov/gds-way/issues/new?body=Problem+with+%27Test-driven+development+%28TDD%29%27+%28https%3A%2F%2Fgds-way.digital.cabinet-office.gov.uk%2Fstandards%2Ftest-driven-development.html%29&amp;labels=bug&amp;title=Re%3A+%27Test-driven+development+%28TDD%29%27">Report problem</a></li>
<li><a href="https://github.com/alphagov/gds-way">GitHub Repo</a></li>
</ul>
</aside>
</div>
</div>
<footer class="govuk-template__footer">
<div class="govuk-footer app-footer" role="contentinfo">
<div class="govuk-footer__meta">
<div class="govuk-footer__meta-item govuk-footer__meta-item--grow">
<ul class="govuk-footer__inline-list">
<li class="govuk-footer__inline-list-item">
<a class="govuk-footer__link" href="/accessibility.html">Accessibility</a>
</li>
</ul>
<svg
aria-hidden="true"
focusable="false"
class="govuk-footer__licence-logo"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 483.2 195.7"
height="17"
width="41"
>
<path
fill="currentColor"
d="M421.5 142.8V.1l-50.7 32.3v161.1h112.4v-50.7zm-122.3-9.6A47.12 47.12 0 0 1 221 97.8c0-26 21.1-47.1 47.1-47.1 16.7 0 31.4 8.7 39.7 21.8l42.7-27.2A97.63 97.63 0 0 0 268.1 0c-36.5 0-68.3 20.1-85.1 49.7A98 98 0 0 0 97.8 0C43.9 0 0 43.9 0 97.8s43.9 97.8 97.8 97.8c36.5 0 68.3-20.1 85.1-49.7a97.76 97.76 0 0 0 149.6 25.4l19.4 22.2h3v-87.8h-80l24.3 27.5zM97.8 145c-26 0-47.1-21.1-47.1-47.1s21.1-47.1 47.1-47.1 47.2 21 47.2 47S123.8 145 97.8 145"
/>
</svg>
<span class="govuk-footer__licence-description">
All content is available under the
<a
class="govuk-footer__link"
href="https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/"
rel="license"
>Open Government Licence v3.0</a>, except where otherwise stated
</span>
</div>
<div class="govuk-footer__meta-item">
<a
class="govuk-footer__link govuk-footer__copyright-logo"
href="https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/uk-government-licensing-framework/crown-copyright/"
>© Crown copyright</a>
</div>
</div>
</div>
</footer>
<script src="/javascripts/govuk_frontend.js" type="module"></script>
<script src="/javascripts/application.js"></script>
</body>
</html>