Test-driven development with Codex: an AI agent builds software against previously defined automated tests

KI-Buster Blog · Coding & AI Development

Test-Driven Development with Codex: Write the Tests First, Then the Code

AI coding agents like Codex can write working code in seconds — but working isn't the same as correct. Test-driven development flips the order: first we define what has to work, then Codex builds the matching code.

Published on October 30, 2026

AI can build entire functions in a matter of seconds today. A short prompt is enough, and suddenly you have Python scripts, JavaScript components, or complete backend endpoints.

The problem: just because AI-generated code works doesn't mean it's correct, safe, or maintainable in the long run.

That's exactly where test-driven development (TDD) comes in. Instead of simply telling an AI "write me this function," we flip the development process around: first we define what has to work, then we let Codex build the matching code.

This approach fundamentally changes the collaboration between humans and AI. A pure code generator becomes a development assistant whose output can be checked against verifiable requirements.

This article explains how test-driven development with Codex works, why a test-first approach is especially useful for AI-generated code, and how to put a complete TDD workflow into practice.

What is test-driven development (TDD)?

Test-driven development is a software development method where automated tests are written before the actual program code exists.

The principle is simple: a test first describes the expected behavior of a function. Then just enough code is written to make that test pass.

The classic TDD cycle in three phases
PhaseDescription
REDWrite a test that fails first
GREENImplement the minimal code that passes it
REFACTORImprove the code, then re-run the tests

The cycle repeats for every new requirement.

Phase 1: RED – write a failing test

Before a function exists, a test is written that describes its expected behavior. The test first has to fail for the right reason — for example, because the function hasn't been implemented yet.

Phase 2: GREEN – write only the necessary code

Now the actual implementation happens. The goal isn't the most elegant solution right away — it's the smallest reasonable implementation that makes the test pass.

Phase 3: REFACTOR – improve the code

Once the tests pass, the code gets reworked. That might mean splitting functions apart, removing duplicate logic, or improving names. Important: after every change, the tests still have to pass.

Why does TDD matter so much for AI-generated code?

Traditionally, developers write code and then check that it works. AI coding agents change that picture: an agent can create several files, change existing functions, and add new dependencies in a short amount of time. That doesn't automatically raise software quality — if anything, mistakes can appear faster and spread across multiple components.

Typical problems with AI-generated code include:

  • Functions miss important edge cases.
  • The code only partially satisfies a vaguely worded requirement.
  • Existing functions break because of a change.
  • Tests only check the successful standard case.
  • The AI agent changes the requirements or the tests so its own implementation appears to succeed.

Test-driven development reduces these risks. The key difference: requirements are translated into executable tests before implementation begins. A test isn't just a technical check — it's a concrete description of the expected behavior.

That said, tests can contain mistakes too. A passing test run doesn't automatically prove that an application is fully correct or secure.

What is Codex, and what role does the AI agent play?

OpenAI Codex is an AI-powered coding agent that helps developers work on software projects. Depending on the environment, Codex can analyze existing project files, edit source code, write tests, run commands, and review changes.

Four capabilities matter especially for TDD:

  • Analyzing requirements: Codex can derive verifiable test cases from a functional description.
  • Implementing tests: the agent writes, for example, pytest, Jest, or Vitest tests.
  • Writing code: it then implements the necessary functionality.
  • Evaluating test results: failing tests can be used to target specific fixes.

The biggest benefit doesn't come from letting Codex run every step unsupervised. It's better to use a clearly defined workflow where a human sets the requirements and acceptance criteria.

A practical example: test-driven development with Codex and Python

We'll build a small Python function that calculates an invoice total including VAT. The function has to meet these requirements:

  • It receives a net amount.
  • The VAT rate is configurable.
  • Negative net amounts are rejected.
  • Invalid tax rates are rejected.
  • The result is rounded to two decimal places using standard commercial rounding.

For this example we'll use Python and pytest.

Step 1: Set up the project

First, create a new project directory.

mkdir codex-tdd-demo
cd codex-tdd-demo

python3 -m venv .venv
source .venv/bin/activate

python -m pip install pytest

On Windows, you'd activate the virtual environment like this instead:

.venv\Scripts\Activate.ps1

Then set up this project structure:

codex-tdd-demo/
├── src/
│   ├── __init__.py
│   └── invoice.py
├── tests/
│   └── test_invoice.py
└── pytest.ini

The file invoice.py stays empty for now. In pytest.ini, add:

[pytest]
pythonpath = .
testpaths = tests

Step 2: Let Codex write only the tests

Now comes the most important part of the TDD workflow. We give Codex a clear instruction: write the tests first, and nothing else.

Work strictly according to Test-Driven Development (TDD).

Write pytest tests only for a function
calculate_gross(net_amount, tax_rate) in src/invoice.py.

Requirements:
- Use Decimal for monetary values.
- Calculate the gross amount including VAT.
- Support tax rates between 0 and 1 inclusive.
- Reject negative net amounts.
- Reject invalid tax rates.
- Round to two decimal places using standard commercial rounding.
- Cover normal cases, zero values, edge cases, and invalid input.

IMPORTANT:
- Do not implement the function yet.
- Do not change any existing application tests.
- Run pytest and document why the new tests fail.
- Stop your work after the RED phase.

This prompt includes an important constraint: Codex isn't allowed to write production code yet. That stops the agent from skipping the test-first approach.

Step 3: Review the tests

A possible test might look like this:

from decimal import Decimal
import pytest

from src.invoice import calculate_gross

def test_gross_amount():
    result = calculate_gross(Decimal("100.00"), Decimal("0.19"))
    assert result == Decimal("119.00")

def test_zero_amount():
    result = calculate_gross(Decimal("0.00"), Decimal("0.19"))
    assert result == Decimal("0.00")

def test_negative_amount():
    with pytest.raises(ValueError):
        calculate_gross(Decimal("-10.00"), Decimal("0.19"))

def test_invalid_tax_rate():
    with pytest.raises(ValueError):
        calculate_gross(Decimal("100.00"), Decimal("1.50"))

These tests check different situations. The last one is especially interesting: it checks that an invalid tax rate gets rejected. Especially with financial calculations, it matters to spell out rounding and validation rules explicitly.

Step 4: RED – the tests have to fail

Now run the tests:

python -m pytest -v

Since the function doesn't exist yet, the import itself fails. A typical error message:

ImportError: cannot import name 'calculate_gross' from 'src.invoice'

That's expected at this stage. The error confirms that the expected function hasn't been implemented yet. It's important to read the error correctly, though: a failed import alone doesn't prove every test case was written correctly. Once the function exists, each individual test actually has to run.

Step 5: GREEN – Codex writes the implementation

Now Codex is allowed to write the actual code. The next prompt:

Now implement only the function calculate_gross() in
src/invoice.py. Use Decimal and ROUND_HALF_UP. Do not change
any tests. Implement only the logic needed to make all the
previously created tests pass. Then run pytest and show the
result.

A possible implementation:

from decimal import Decimal, ROUND_HALF_UP

def calculate_gross(net_amount: Decimal, tax_rate: Decimal) -> Decimal:
    if not isinstance(net_amount, Decimal):
        raise TypeError("net_amount must be Decimal")
    if not isinstance(tax_rate, Decimal):
        raise TypeError("tax_rate must be Decimal")
    if not net_amount.is_finite():
        raise ValueError("Invalid net amount")
    if not tax_rate.is_finite():
        raise ValueError("Invalid tax rate")
    if net_amount < 0:
        raise ValueError("Negative amounts are not allowed")
    if not Decimal("0") <= tax_rate <= Decimal("1"):
        raise ValueError("Invalid tax rate")

    gross = net_amount * (Decimal("1") + tax_rate)
    return gross.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)

The function validates the input first, then calculates the gross amount, then rounds the result to two decimal places. For a net amount of 100 euros and a 19 percent VAT rate, the gross amount comes out to 119.00 euros.

After implementing it, we run the tests again. With a correct setup and unchanged sample tests, the result should look like this (a sample output, not an actually executed test run here):

================ test session starts ================
collected 4 items

tests/test_invoice.py ....                     [100%]

================= 4 passed ==========================

That's the GREEN phase done.

Step 6: REFACTOR – Codex improves the code

Once the tests pass, Codex can improve the implementation. For instance, the agent could move repeated validation logic into a helper function. The matching prompt:

Review the existing implementation for readability,
maintainability, and unnecessary repetition. Refactor the
code without changing its observable behavior. Existing
tests must not be changed. Then run the full test suite
and document the changes.

What matters is that the refactoring doesn't introduce any new functional requirements. The code should improve without changing its existing behavior.

A Codex TDD workflow: how an AI agent should work

In larger projects, a single prompt often isn't enough. A fixed working instruction that Codex follows for every new function helps here.

You work strictly according to Test-Driven Development (TDD).

1. First analyze the requirements and existing tests.
2. Write verifiable acceptance criteria.
3. Write new tests before the implementation.
4. Run the tests and document the RED phase.
5. Implement the smallest reasonable solution.
6. Run all relevant tests and document GREEN.
7. Refactor without changing behavior.
8. Re-run the full relevant test suite.
9. Never change tests just to make broken code pass.
10. Explicitly flag unclear requirements and tests that
    cannot be run.

Work in small, traceable steps. At the end, report on the
changes made, the test commands used, the test results, and
any remaining risks.

This instruction can, for example, be stored as a project rule in an AGENTS.md file so Codex applies the same working rules on later development tasks. For how to cleanly separate such an AGENTS.md from a CLAUDE.md for Claude Code, see AGENTS.md vs. CLAUDE.md: Which File Does Your AI Coding Project Need? (Read article).

That said, project instructions like this are not unchangeable technical safety boundaries. For binding checks, you should also use CI pipelines, permissions, and branch protection rules.

What kinds of tests can Codex write?

Test-driven development isn't limited to simple unit tests. Depending on the project, different test types can make sense.

Test types, typical use, and tools
Test typeTypical useTools
Unit testsIndividual functions and methodspytest, Jest, Vitest
Integration testsMultiple components working togetherpytest, Testcontainers
API testsHTTP endpoints and responsespytest, Supertest
UI testsUser interaction and operationPlaywright
Regression testsKeep already-fixed bugs fixedpytest, Jest
Property-based testsCheck general properties across many inputsHypothesis

A practical example: if Codex is building a REST API, tests for successful responses, invalid input, missing permissions, and error cases can be written first. Only after that does the agent implement the matching endpoints — so the expected API behavior gets defined before the actual development happens.

Using TDD with Codex in existing projects

Test-driven development is especially useful when extending an application that already exists. Say an existing Flask backend needs a new API function. Without a test-first approach, Codex could change several files directly.

With TDD, development becomes more controlled: the agent first analyzes the existing endpoints and tests, then writes additional tests for the desired feature, then implements the change and checks both the new tests and the existing test suite. That way, unintended behavior changes surface earlier.

A good Codex instruction for a bug fix with a regression test might read: "Analyze the reported bug. First write a regression test that reproduces it. Run the test and confirm it fails because of the described bug. Then fix the root cause without changing the test. Finally, run all relevant tests."

This approach has a long-term benefit: the bug doesn't just get fixed — it stays verifiably fixed through the regression test. On later changes, that test can stop the same bug from silently coming back.

The five most common TDD mistakes with Codex

1. Codex writes tests and the implementation at the same time. When tests and code appear in one single, uncontrolled step, you lose a key benefit of the test-first approach. Better: run RED, GREEN, and REFACTOR as separate, distinct steps.

2. Tests get adjusted to match broken code. An AI agent might try to change a failing test so it matches the existing implementation instead. That strips the test of its purpose as an independent requirement. Better: set acceptance criteria upfront, and review any change to an existing test separately.

3. Only the happy path gets tested. A function works for normal input but fails on zero values, invalid data, or edge cases. Better: explicitly ask Codex for negative tests, boundary analysis, and error cases.

4. A passing test run gets mistaken for full quality. Four or five passing unit tests say very little about authentication, security, concurrency, or real production load. Better: supplement unit tests with integration tests, security reviews, and code review.

5. Too much changes at once. When Codex changes many functions at the same time, it becomes harder to trace a bug back to a specific change. Better: use small, clearly scoped tasks, each with its own tests.

For broader pitfalls in AI-assisted coding that go beyond TDD specifically, see Getting Started with Vibe Coding: 10 Mistakes to Avoid (Read article).

How do you stop Codex from simply rewriting tests?

One of the most important questions in AI-assisted TDD is: what happens when the agent fails a test and changes it instead of fixing the code?

That's exactly why important tests shouldn't be protected by prompt instructions alone. In professional projects, additional technical controls make sense, for example:

  • Review tests and implementation in separate commits.
  • Require changes to core test files to go through pull requests.
  • Run CI tests independently of the local Codex working directory.
  • Use protected branches and mandatory reviews.
  • Define security-relevant acceptance tests independently of the agent implementing the change.

Separating the agent that writes the code from the entity that evaluates its output is especially valuable. That can be a human developer, a separate review agent, or a combination of automated CI checks and manual review. One important point: a second AI agent isn't automatically independent or more reliable — its results still need to be verifiable too.

For how to use Codex safely overall — from Git and sandbox environments to backups and approvals — see How to Use OpenAI Codex Safely: Git, Sandbox, Backups, and Approvals (Read article).

Automating TDD with Codex and GitHub Actions

To make sure tests don't only run locally, a CI pipeline is worth setting up. For the Python example, a simple GitHub Actions configuration looks like this.

File: .github/workflows/tests.yml

name: Python Tests

on:
  push:
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install pytest

      - name: Run tests
        run: |
          python -m pytest -v

The pipeline runs on pushes and pull requests and executes the tests in a separate environment. For production projects, dependencies should be pinned reproducibly, and the GitHub Actions you use should ideally be pinned to reviewed commit SHAs.

Combined with branch protection rules, failing tests can stop changes from landing on the main branch without further review. For a detailed look at building a controlled GitHub workflow with Codex, see How to Use Codex with GitHub: Branches, Pull Requests, and Code Reviews (Read article). That's how TDD turns from a development method into a fixed part of the software quality process.

Classic development vs. Codex without TDD vs. Codex with TDD

Classic development, Codex without TDD, and Codex with TDD compared
CriterionClassic, no TDDCodex, no TDDCodex with TDD
ImplementationManualAI-assistedAI-assisted
Tests before codeNoUsually notYes
Requirements verifiableVariesVariesMade concrete through tests
Error detectionDepends on reviewDepends on reviewEarly, automated feedback
Regression testsOptionalOptionalA fixed part of the process
RefactoringManualAI-assistedAI-assisted, test-backed
Human oversightRequiredRequiredStill required

TDD doesn't automatically make Codex a better programmer. But the method does make development work more structured, and lets you check results more systematically.

Which projects benefit from test-driven development with Codex?

This approach fits especially well for applications where correct behavior can be described clearly — backend functions, REST APIs, data validation, business logic, calculations, and bug fixes, for example. TDD can also be worthwhile for existing software projects when new features get added without breaking existing behavior.

The benefit is less clear-cut for purely exploratory work, early design prototypes, or requirements that are still changing a lot. Tests still help there too — but the classic, strict RED-GREEN-REFACTOR cycle doesn't have to be the most economical approach for every small change. What matters is that the testing effort matches the risk and complexity of the application.

Best practices: using Codex for more reliable software development

A clear process is worth setting up for production use. A TDD checklist for your next Codex project:

  • Requirements and acceptance criteria defined
  • Tests written before the implementation
  • RED phase traceably verified
  • Implementation done without changing tests
  • GREEN phase successfully completed
  • Refactoring done with tests re-run afterward
  • Existing test suite and CI checked
  • Changes and remaining risks documented

One extra tip: document not just which tests exist in your project, but why they were written. That keeps the underlying intent traceable even once Codex has reworked larger parts of the implementation later on.

Frequently asked questions about test-driven development with Codex

Can Codex automatically write unit tests?

Yes. Codex can derive automated tests from requirements and existing source code. How reliable those tests are depends on the quality of the requirements, the project context, and the review that follows.

Do I need to know how to code to use TDD with Codex?

Basic programming knowledge is very helpful. Codex can make writing tests and code easier, but it doesn't replace understanding requirements, edge cases, and software quality.

Does TDD with Codex also work for JavaScript and TypeScript?

Yes. Besides Python, JavaScript and TypeScript projects can also be developed test-first using Jest or Vitest.

Can Codex automatically fix existing tests?

Codex can analyze failing tests and propose changes. First, though, it should be clear whether the problem actually lies in the test or in the implementation. Tests shouldn't simply be adjusted to force a passing run.

Is TDD with Codex slower than direct AI coding?

The first development steps can take more time, since requirements and tests are defined upfront. In return, mistakes can surface earlier and later fixes can become simpler. Whether this saves time overall depends on the project.

Can I let Codex work fully autonomously with TDD?

Technically, many steps can be automated. For production use, though, human approvals, independent review, and appropriate permission limits are still advisable.

Conclusion: tests first, code second – even with AI

Test-driven development isn't a new idea. But AI coding agents like Codex give the method new relevance. As AI can produce software faster and faster, the question of how to control its quality matters more.

A test-first approach gives you a structured way to do that. Instead of accepting code blindly, you first define what behavior is expected. Codex then implements a matching solution and verifies it against automated tests.

The key insight: it's not the speed at which AI writes code that determines an application's quality — it's how well requirements, implementation, and verification work together.

Combining Codex with clear acceptance criteria, test-driven development, and automated CI checks builds a much stronger foundation for traceable, maintainable software.

For how to additionally use Codex for targeted security and quality reviews, see Code Reviews with Codex: Catching Bugs Before They Reach Production (Read article).

More practical guides on Codex, AI agents, and software development are available on the KI-Buster blog.

Editorial review date: October 30, 2026. The code samples, prompts, and worked example are simplified, original illustrations for demonstration purposes only; no measured productivity gains or conducted project tests are claimed.