Tdd With Phpunit (Symfony)
Use when
- Driving a feature with RED-GREEN-REFACTOR using PHPUnit 10/11 class-based tests.
- Choosing between
TestCase, KernelTestCase and WebTestCase for a new behavior.
- Testing a console command, or an invalid form that must answer 422.
- Swapping an external service for a double through the test container.
Default workflow
- RED: pick the base class, write the test with
#[Test], #[DataProvider] and #[CoversClass], run it and check it fails for the right reason.
- GREEN: write the minimum code that passes.
- REFACTOR with the suite green, re-running it after each change.
- Replace an external boundary with
static::getContainer()->set(Service::class, $mock).
- Test commands with
CommandTester, or with runCommand() and assertCommandIsSuccessful() on Symfony 8.1+.
- Assert invalid form submissions with
assertResponseIsUnprocessable().
Guardrails
- Use PHPUnit 10+ attributes, not
@test or @dataProvider annotations.
- Fetch services with
static::getContainer(), not the legacy self::$container.
- Mock only true external boundaries (HTTP clients, third-party SDKs); keep real services and a real database elsewhere.
runCommand() and closures in getContainer()->set() need Symfony 8.1+.
Progressive disclosure
- Use this file for execution posture and risk controls.
- Open references when deep implementation details are needed.
Output contract
- The failing PHPUnit output (RED), then the passing run.
- Test files changed, with the base class and attributes used.
- Commands executed.
References