project-testinglisted
Install: claude install-skill ubermuda/loupe
# Testing, PHPUnit patterns
## WebTestCase, mocking services across multiple requests
Call `$client->disableReboot()` whenever a mock must survive a GET then POST sequence. Symfony shuts the kernel down after each `$client->request()` call, which discards any `getContainer()->set(ServiceClass::class, $mock)` override. The next `submitForm()` call boots a fresh kernel and uses the real service. Add `disableReboot()` before the first request in any test that both mocks a service and makes two or more HTTP requests.
```php
$client = static::createClient();
$client->disableReboot(); // keep mock alive across GET + submitForm
$this->mockExternalService($data);
$client->request('GET', '/confirm?id=123');
$client->submitForm('Save', [...]);
```
You need this only when the handler, and not just the controller, calls the mocked service. Moving an API call from the controller's GET prefill into the command handler's POST flow is the usual trigger.
## Controller integration tests, assert DB state
For POST endpoints (create, update, delete, attach, detach), assert the database outcome, not only the redirect. A test that asserts only `assertResponseRedirects(...)` tests routing. Assert after you follow the redirect.
```php
$em->clear(); // discard identity-map cache
$fetched = $em->find(Project::class, $project->id);
self::assertNull($fetched); // for a delete
// or
self::assertNotNull($fetched->repository); // for an attach
```
### Stale identity-map state in test setup