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"
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user