.claude/skills/testing-symfony/SKILL.md
Stratégie de Tests Symfony 8.0 / PHP 8.5. Use when writing tests, reviewing test coverage, or setting up testing.
npx skillsauth add thebeardedbearsas/claude-craft testing-symfonyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Versions : Symfony 8.0+ | PHP 8.5 | Pest 4.5+ | PHPUnit 13+ | Playwright
| Type | Outil | Usage | |------|-------|-------| | Unit/Integration | Pest 4.5+ (PHPUnit 13, arch tests) | Tests backend Symfony | | Browser/E2E | Pest 4 Browser Testing (Playwright natif) | Tests frontend intégrés | | Mutation | Infection | Qualité des tests (MSI >= 80%) | | Static Analysis | PHPStan Level 10 | Vérification statique |
Abandonner : Panther (lourd, complexe) et Behat (verbeux). Pest 4 intègre tout.
Sources : Pest 4, Infection
// Pest.php
<?php
use Symfony\Component\Panther\PantherTestCase;
pest()->extend(Tests\TestCase::class)->in('Feature');
pest()->extend(Tests\TestCase::class)->in('Unit');
// Browser testing
pest()->extend(PantherTestCase::class)->in('Browser');
// Arch tests
pest()->arch('strict types')
->expect('App')
->toUseStrictTypes();
pest()->arch('no helpers')
->expect('App')
->not->toUse(['dd', 'dump']);
Source : Pest 4 Configuration
// tests/Unit/Service/OrderServiceTest.php
<?php
use App\Service\OrderService;
use App\Entity\Order;
test('create order returns order with id', function () {
// Arrange
$service = new OrderService($this->getEntityManager());
// Act
$order = $service->create(['customer' => 'Alice']);
// Assert
expect($order)->toBeInstanceOf(Order::class)
->and($order->getId())->not->toBeNull()
->and($order->getCustomer())->toBe('Alice');
});
Plus besoin de Panther ou configuration externe — Playwright natif dans Pest 4.
// tests/Browser/LoginTest.php
<?php
test('user can login', function () {
$this->browse(function (Browser $browser) {
$browser->visit('/login')
->type('email', '[email protected]')
->type('password', 'secret')
->press('Login')
->assertPathIs('/dashboard')
->assertSee('Welcome Alice');
});
});
test('login validates email format', function () {
$this->browse(function (Browser $browser) {
$browser->visit('/login')
->type('email', 'invalid-email')
->type('password', 'secret')
->press('Login')
->assertSee('Please provide a valid email');
});
});
Source : Pest 4 Browser Testing
Presets réutilisables pour valider l'architecture.
// tests/Arch/ArchitectureTest.php
<?php
// Clean Architecture — Domain ne dépend pas d'Infrastructure
pest()->arch('domain is independent')
->expect('App\Domain')
->not->toUse(['App\Infrastructure', 'Doctrine\ORM']);
// Use Cases utilisent des interfaces
pest()->arch('use cases depend on abstractions')
->expect('App\Application\UseCase')
->toOnlyUse(['App\Domain', 'App\Application\Port']);
// Controllers respectent le namespace
pest()->arch('controllers in correct namespace')
->expect('App\Presentation\Controller')
->toBeClasses()
->toHaveSuffix('Controller')
->toOnlyBeUsedIn(['App\Presentation']);
// Pas de dd() ou dump() en prod
pest()->arch('no debug helpers')
->expect(['dd', 'dump', 'var_dump'])
->not->toBeUsedIn('App');
Source : Pest Arch Testing
# composer.json
{
"require-dev": {
"infection/infection": "^0.29"
}
}
# infection.json5
{
"source": { "directories": ["src"] },
"logs": { "badge": { "branch": "main" } },
"mutators": { "@default": true },
"minMsi": 80,
"minCoveredMsi": 85
}
# Exécution
vendor/bin/infection --threads=4
Philosophie : "Code coverage = quantité. MSI (Mutation Score Indicator) = qualité."
Source : Infection
// tests/Feature/Api/UserApiTest.php
<?php
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
test('get user returns 200', function () {
$client = static::createClient();
$client->request('GET', '/api/users/123');
expect($client->getResponse()->getStatusCode())->toBe(200)
->and(json_decode($client->getResponse()->getContent(), true))
->toHaveKey('id')
->toHaveKey('email');
});
test('create user validates email', function () {
$client = static::createClient();
$client->request('POST', '/api/users', [], [], ['CONTENT_TYPE' => 'application/json'], json_encode([
'name' => 'Bob',
'email' => 'invalid',
]));
expect($client->getResponse()->getStatusCode())->toBe(422);
});
// tests/Fixtures/UserFixtures.php
<?php
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use App\Entity\User;
class UserFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
$user = new User();
$user->setEmail('[email protected]');
$user->setPassword('hashed_password');
$manager->persist($user);
$manager->flush();
$this->addReference('user_alice', $user);
}
}
# phpstan.neon
parameters:
level: 10
paths:
- src
- tests
excludePaths:
- src/Kernel.php
checkMissingIterableValueType: true
checkGenericClassInNonGenericObjectType: true
reportUnmatchedIgnoredErrors: true
Source : PHPStan
Voir @.claude/rules/07-testing.md pour principes transverses.
tools
Third-party Claude Code token/context/code-review tools. Use when choosing or recommending an external tool to reduce token usage, manage context, or review large codebases.
development
--- name: value-objects description: Règle 04 : Value Objects. Use when implementing DDD patterns. --- # Règle 04 : Value Objects This skill provides guidelines and best practices. See ../../rules/18-value-objects.md for detailed documentation.
development
Sécurité & RGPD - Atoll Tourisme. Use when reviewing security, implementing auth, or hardening code.
tools
Outils de qualité - Atoll Tourisme. Use when setting up quality tools or CI.