docs: add TDD conventions and testing guide to CLAUDE.md
Covers testing file conventions, Red→Green→Refactor cycle with example prompts, common anti-patterns, test runner commands, and the auto-run hook setup. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,106 @@ curl "http://localhost:8080/graph.svg?theme=dark" -o graph.svg
|
|||||||
curl "http://localhost:8080/health"
|
curl "http://localhost:8080/health"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Testing conventions (apply to every test file)
|
||||||
|
|
||||||
|
- `declare(strict_types=1)` at the top of every test file
|
||||||
|
- Test classes are `final` and extend `TestCase`
|
||||||
|
- Methods: `#[Test]` attribute + `it_` prefix + `snake_case` — e.g. `it_returns_empty_when_no_contributions`
|
||||||
|
- Structure: Arrange → Act → Assert, separated by blank lines; one assertion per test when possible
|
||||||
|
- Use `$this->assert*()` not `self::assert*()`
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Service;
|
||||||
|
|
||||||
|
use App\Service\SvgRenderer;
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
final class SvgRendererTest extends TestCase
|
||||||
|
{
|
||||||
|
#[Test]
|
||||||
|
public function it_renders_an_svg_with_no_contributions(): void
|
||||||
|
{
|
||||||
|
$renderer = new SvgRenderer();
|
||||||
|
|
||||||
|
$svg = $renderer->render([], 'light');
|
||||||
|
|
||||||
|
$this->assertStringContainsString('<svg', $svg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### TDD: Red → Green → Refactor
|
||||||
|
|
||||||
|
Always drive new features and bug fixes with this cycle. Claude writes implementation first by default — override that with explicit prompts.
|
||||||
|
|
||||||
|
**Phase 1 — Red (write a failing test first)**
|
||||||
|
|
||||||
|
```
|
||||||
|
Write a failing test for [feature description].
|
||||||
|
Do NOT write the implementation yet.
|
||||||
|
The test should fail because the class/method does not exist.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Phase 2 — Green (minimal implementation)**
|
||||||
|
|
||||||
|
```
|
||||||
|
The tests are written and failing. Now implement the minimum code to make them pass. Nothing more.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Phase 3 — Refactor**
|
||||||
|
|
||||||
|
```
|
||||||
|
Tests are green. Refactor the implementation for [readability / removing duplication / naming].
|
||||||
|
Run php bin/phpunit after each change to confirm tests stay green.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Common anti-patterns**
|
||||||
|
|
||||||
|
| Wrong prompt | Why it breaks TDD | Correct prompt |
|
||||||
|
|---|---|---|
|
||||||
|
| "Write tests for this feature" | Claude implements first, then fits tests to it | "Write **failing** tests for [feature]. Stop before any implementation." |
|
||||||
|
| "Add tests and implementation" | Loses the design feedback of failing tests | Two separate prompts: Red, then Green |
|
||||||
|
| "Make the tests pass" | Encourages skipping to a green state | "Implement the minimum to make the failing tests pass." |
|
||||||
|
| Combining Red + Green in one request | No failing baseline | Always separate the two phases |
|
||||||
|
|
||||||
|
### Running tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run full suite
|
||||||
|
php bin/phpunit
|
||||||
|
|
||||||
|
# Run with human-readable output
|
||||||
|
php bin/phpunit --testdox
|
||||||
|
|
||||||
|
# Run a single test file
|
||||||
|
php bin/phpunit tests/Unit/Service/SvgRendererTest.php
|
||||||
|
|
||||||
|
# Run tests matching a filter
|
||||||
|
php bin/phpunit --filter it_renders
|
||||||
|
```
|
||||||
|
|
||||||
|
### Auto-run hook
|
||||||
|
|
||||||
|
Add to `.claude/settings.json` to run PHPUnit automatically after every file edit:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"hooks": {
|
||||||
|
"PostToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "Edit|Write",
|
||||||
|
"command": "php bin/phpunit 2>&1 | tail -20"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
Reference in New Issue
Block a user