Training · Intermediate
Test-Driven Development with AI Agents
As long as it is fast? Using tests to specify what an AI agent implements
- Scope 6 sessions of 2 hours
- Format Live via Zoom
- Language German
- Price per person €1,199
What it is about
An AI agent delivers code in minutes that would take you hours. Without a solid foundation, though, this speed quickly turns into recklessness instead of progress. If nobody has specified beforehand what the code is supposed to do, the tests are written afterwards and adapt to the code instead of the other way round, and the review cannot keep up. That leads to technical debt and fragile systems.
The way forward is a way of working that existed long before agents: test-driven development. You write a failing test first, and then only as much code as that test demands. This produces lean, fully tested code whose design follows from the tests. If you master TDD, you benefit from it with and without AI.
With an agent, the test becomes the specification. You define what the code is supposed to do, the agent delivers the implementation, and an automated quality gate decides whether it is good enough. Along the way you see that the same practices make working with AI agents safe and let people work fast.
In this training you learn TDD from the ground up, without AI in the first four sessions, because the rest does not work without this foundation. You practise it in ensemble programming: everyone works on one task together, with one screen and the roles of driver, navigator, and facilitator, which change regularly. In the last two sessions you transfer this way of working to your own AI agent: the specification is written in the ensemble, you work with your agent on your own or in pairs, and the review takes place together.
The example project
One continuous example project accompanies you through the training: EventFlow, a system for ticketing and seat reservations with domain, application, and infrastructure layers. The toolchain comes preconfigured: composer ci is a quality gate with five stages, namely coding standard, static analysis with PHPStan at level 10, architecture rules with Deptrac, tests with PHPUnit, and mutation testing with Infection. Instead of building it, you read and sharpen it, and you complete the setup before the first session. For the first steps in the TDD cycle there is also a kata in which a list of appointments is to be presented in an appealing way, one requirement at a time.
Between the sessions, short assignments prepare the next session. The most important one follows the fourth session: you get your own agent ready for work in the example project.
Programme
-
Session 1: Speed needs a safety net
What does each stage of the gate catch?
- The thesis: speed alone leads to recklessness, control alone to standstill, and the way forward is velocity with a safety net
- Feedback loops from the type system, tests, architecture, and production, each of which catches different defects
- A tour of the toolchain:
composer ciwith its five stages,phpunit.xml,phpstan.neon,deptrac.yaml,infection.json5.dist, and the CI workflow - Planting defects live: each stage reports something different
- The agent as a very fast, very self-confident intern
Result: A project that runs, in which you have seen every stage of the gate catch something in your own code, and the value object
Money, developed test-first and without AI, withcomposer cigreen -
Session 2: The TDD cycle
How much test does the next step need?
- Writing the test first gives you a specification, implementing first only an incomplete record
- The guiding test: starting from the outside and recording the goal
- Small steps, fake it, and triangulation
- Weak and strong tests: both are green, but only one kills the mutant, and you read the output of Infection together
- Ensemble programming: roles, rotation, rules
Result: Several requirements of the appointments kata, implemented in the ensemble with a guiding test and in the rhythm of red, green, and refactor
-
Session 3: Chicago or London
From the inside out or from the outside in?
- Inside-out (Chicago): starting from the domain core, verifying state
- Outside-in (London): discovering collaborators from the use case, verifying their communication, test doubles as a design tool
- What makes code testable: clear responsibilities and loose coupling, such as passing the time as a parameter instead of reading it from a clock
- Ports and adapters, using the payment seam of EventFlow as the example
Result: The aggregate
EventwithReservation, developed inside-out in the ensemble, in which a seat can only be reserved once and no reservation is possible after the event has started, and outside-in seen on an example of its own -
Session 4: Refactoring
When and how do you clean up without breaking anything?
- When to refactor: after every green, before the next requirement comes
- Refactoring production code and test code, with tests that verify behaviour instead of implementation details
- Recording and verifying domain events
- Mutation testing on the aggregate: which mutant survives, and why
Result: A refactored aggregate with the domain event
SeatReserved, and an analysis of the surviving mutants that tells gaps in the tests from equivalent mutants -
Session 5: Tests as a specification for the agent
What do you need to specify so that the agent builds the right thing?
- The reversal: instead of “Write me a class that can do X”, it is now “Make these tests pass without changing them”
- The order: red acceptance tests, architecture rules, the agent implements until
composer ciis green, review of the domain logic, mutation testing - Writing a briefing for the agent, and stopping the agent
- The joint review: unexpected dependencies, logic in the wrong layer, surviving mutants, changed tests
Result: The use case
PurchaseTicket, specified in the ensemble without AI and implemented by your agent, and a joint review of its result -
Session 6: Hardening the quality gate, and the transfer
What stops bad code, no matter where it comes from?
- Branch protection as the actual safety net, because anything can be skipped locally
- Objective gates instead of policies such as “AI code must be labelled”
- Costs and benefits: which gates run on every commit, which before the merge, and which at night
- Live: required status checks and a locked merge button
- Sharpening and breaking the gate: a threshold for the mutation score, protection against a growing PHPStan baseline, mandatory tests for new classes, and deliberately bad commits, written by you or generated by the agent, because the gate is blind to where code comes from
Result: A sharpened gate that blocks every bad commit, whether from a human or a machine, and a plan for the order in which you add the missing gates to your project, and which one comes on Monday
Who it is for
- PHP developers who want to develop their software purposefully and with high quality
- Developers and teams who use AI agents or want to introduce them without giving up control over quality
- Everyone who knows TDD only from hearsay, or who has tried it before and given up
Prerequisites
- Practical experience with PHPUnit and knowledge of object-oriented programming in PHP; if you do not write tests yet, start with “Understanding Testing” and “Agentic PHPUnit”
- For the exercises, a local environment with PHP 8.5, Xdebug or PCOV, Git, and an IDE, or alternatively Podman or Docker with the Containerfile provided
- From the fifth session on, an AI agent of your choice, such as Claude Code, Copilot Agent Mode, or Cursor, that is allowed to write files and run commands in the project; you cover the cost and usage quota of your agent yourself; if you are not allowed to use an agent at your company, you work together with another participant
What you take away
- You develop a feature test-first, from the guiding test to the refactored code
- You decide with good reason whether to work inside-out or outside-in
- You express requirements as tests that an AI agent has to satisfy without being allowed to change them
- You assess the code of an agent with a quality gate and mutation testing instead of by eye
- You know which gate you add to your project first, and why
Your trainer
Sebastian Bergmann is the creator of PHPUnit, the de facto standard for testing PHP code. Since 2001 he has been helping teams build maintainable and well-tested software as a consultant and trainer, since 2009 as a co-founder of thePHP.cc.