Files
Mangarr/.cursor/rules/tests.mdc

202 lines
5.1 KiB
Plaintext

---
description:
globs: *.php
alwaysApply: false
---
# Tests de Mangarr
## Structure des Tests
L'application suit une organisation stricte des tests reflétant l'architecture hexagonale :
```
tests/
├── Domain/ # Tests unitaires par domaine
│ ├── Manga/
│ │ ├── Application/ # Tests des cas d'utilisation
│ │ ├── Domain/ # Tests du cœur métier
│ │ └── Adapter/ # Implémentations InMemory des ports
│ ├── Reader/
│ │ └── ...
│ └── Scraping/
│ └── ...
├── Feature/ # Tests fonctionnels par domaine
│ ├── Manga/
│ ├── Reader/
│ └── Scraping/
├── Shared/ # Tests et adapters partagés
│ └── Adapter/ # Adapters partagés entre domaines
└── Fixtures/ # Fixtures de test partagées
```
## Règles de Test
### 1. Tests Unitaires (Domain)
- Localisation : `tests/Domain/NomDuDomain/`
- Principes :
- Tester chaque composant de manière isolée
- Éviter l'utilisation de mocks
- Utiliser des adapters InMemory
- Nommer les classes de test avec le suffixe `Test`
### 2. Adapters de Test
- Localisation : `tests/Domain/NomDuDomain/Adapter/`
- Principes :
- Implémenter les interfaces du domaine
- Stocker les données dans des tableaux
- Préfixer les classes avec `InMemory`
- Si utilisé par plusieurs domaines → déplacer dans `tests/Shared/Adapter/`
### 3. Tests Fonctionnels (Feature)
- Localisation : `tests/Feature/NomDuDomain/`
- Principes :
- Tester les endpoints HTTP
- Utiliser le trait `ResetDatabase`
- Tester le flux complet
- Nommer les classes avec le suffixe `Test`
## Exemples de Code
### 1. Adapter InMemory
```php
namespace Tests\Domain\Manga\Adapter;
use App\Domain\Manga\Domain\Entity\Manga;
use App\Domain\Manga\Domain\Repository\MangaRepositoryInterface;
class InMemoryMangaRepository implements MangaRepositoryInterface
{
/** @var array<string, Manga> */
private array $mangas = [];
public function save(Manga $manga): void
{
$this->mangas[$manga->getId()->toString()] = $manga;
}
public function get(string $id): ?Manga
{
return $this->mangas[$id] ?? null;
}
public function clear(): void
{
$this->mangas = [];
}
}
```
### 2. Test Unitaire
```php
namespace Tests\Domain\Manga\Application;
use App\Domain\Manga\Application\Command\CreateMangaCommand;
use App\Domain\Manga\Application\CommandHandler\CreateMangaCommandHandler;
use Tests\Domain\Manga\Adapter\InMemoryMangaRepository;
use PHPUnit\Framework\TestCase;
class CreateMangaCommandHandlerTest extends TestCase
{
private InMemoryMangaRepository $repository;
private CreateMangaCommandHandler $handler;
protected function setUp(): void
{
$this->repository = new InMemoryMangaRepository();
$this->handler = new CreateMangaCommandHandler($this->repository);
}
public function test_it_creates_manga(): void
{
// Given
$command = new CreateMangaCommand('One Piece');
// When
$this->handler->__invoke($command);
// Then
$mangas = $this->repository->findAll();
$this->assertCount(1, $mangas);
$this->assertEquals('One Piece', $mangas[0]->getTitle()->value());
}
}
```
### 3. Test Fonctionnel
```php
namespace Tests\Feature\Manga;
use Tests\Shared\ResetDatabase;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class CreateMangaTest extends WebTestCase
{
use ResetDatabase;
public function test_it_creates_manga_through_api(): void
{
// Given
$client = static::createClient();
$data = ['title' => 'One Piece'];
// When
$client->request('POST', '/api/mangas', [], [], [], json_encode($data));
// Then
$this->assertResponseIsSuccessful();
$this->assertJsonContains(['title' => 'One Piece']);
}
}
```
### 4. Adapter Partagé
```php
namespace Tests\Shared\Adapter;
use App\Domain\Shared\Contract\MessageBusInterface;
class InMemoryMessageBus implements MessageBusInterface
{
/** @var array<object> */
private array $messages = [];
public function dispatch(object $message): void
{
$this->messages[] = $message;
}
public function getDispatchedMessages(): array
{
return $this->messages;
}
public function clear(): void
{
$this->messages = [];
}
}
```
## Bonnes Pratiques
### 1. Organisation des Tests
- Un test par classe
- Regrouper les tests par fonctionnalité
- Suivre la même structure que le code source
- Utiliser des données de test explicites
### 2. Nommage
- Classes de test : `{ClassTestée}Test`
- Méthodes de test : `test_it_{comportement_testé}`
- Adapters : `InMemory{Interface}`
### 3. Assertions
- Utiliser des assertions spécifiques
- Vérifier les états plutôt que les interactions
- Tester les cas d'erreur
- Tester les cas limites
### 4. Données de Test
- Utiliser des fixtures pour les données complexes
- Créer des données spécifiques au test quand possible
- Éviter les dépendances entre tests
- Nettoyer l'état après chaque test