Aller au contenu

Stratégie de tests

Philosophie

Règle d'or

Un test doit tester un comportement métier, pas une implémentation technique. Préférez "quand une partie est créée, une invitation est envoyée" à "quand create() est appelé, save() est appelé sur le mock".


Pyramide de tests

           /\
          /E2E\          Playwright — Parcours utilisateurs complets
         /─────\
        / Intég \        Pest Feature — Endpoints API, DB
       /─────────\
      /  Unitaire \      Pest Unit + Vitest — Services, composants isolés
     /─────────────\
Couche Outil Commande Couverture cible
Unitaires backend Pest PHP make test 90%+
Intégration backend Pest PHP Feature make test 80%+
Architecture Pest Arch make test-arch 100% boundaries
Unitaires frontend Vitest make test-frontend 80%+
E2E Playwright make test-e2e Parcours critiques

Couverture de code

  • Seuil minimum : 80% (lignes, fonctions, branches, statements)
  • Objectif : 90%+
  • Outil backend : pcov (extension PHP) — --coverage --min=80
  • Outil frontend : @vitest/coverage-v8

Exclusions de couverture backend (phpunit.xml)

Les fichiers suivants sont exclus du calcul (pas de logique métier) :

<source>
    <exclude>
        <directory>app/Providers/</directory>  <!-- Service providers (configuration) -->
        <file>app/Models/User.php</file>        <!-- Modèle Eloquent auto-généré -->
    </exclude>
</source>

Isolation de la base de données de test

PHPUnit 12 + Docker : balises <server> obligatoires

Lorsque les tests PHPUnit/Pest tournent dans un conteneur Docker, les variables d'environnement injectées par Docker Compose (DB_DATABASE, etc.) sont présentes dans $_SERVER. Or Laravel lit $_SERVER en priorité via son helper env(). Les balises <env force="true"/> de PHPUnit 12 mettent à jour putenv() et $_ENV mais pas $_SERVER. Il faut donc aussi des balises <server> dans phpunit.xml pour garantir que les tests utilisent bien primatch_test et non la base principale.

<!-- phpunit.xml — les deux types de balises sont nécessaires -->
<env name="DB_DATABASE" value="primatch_test" force="true"/>
<server name="DB_DATABASE" value="primatch_test"/>

Sans les balises <server>, RefreshDatabase exécute migrate:fresh sur la base principale, vidant toutes les données utilisateur et métier.

Configuration frontend (vitest.config.ts)

coverage: {
    thresholds: {
        lines: 80,
        functions: 80,
        branches: 80,
        statements: 80,
    },
}
make test-coverage           # Backend avec couverture HTML
make test-coverage-frontend  # Frontend avec couverture LCOV + HTML

Quoi tester par couche

Tests unitaires (Domain)

  • ✅ Services métier (MatchService, etc.)
  • ✅ Value Objects (Score, Niveau)
  • ✅ DTOs (validation, transformation)
  • ❌ Pas les Repositories (testés en intégration)

Tests d'intégration (Http + DB)

  • ✅ Controllers (endpoint → réponse JSON)
  • ✅ Form Requests (validation des inputs)
  • ✅ Repositories (vraie DB de test primatch_test)
  • ✅ Events et Listeners

Tests E2E (Playwright)

  • ✅ UC-AUTH-001 : Inscription par OTP
  • ✅ UC-AUTH-002 : Connexion par OTP
  • ✅ UC-PARTIE-001 : Créer une partie
  • ✅ UC-PARTIE-004 : Saisir et valider un score (4 joueurs)

Cas à toujours couvrir

Pour chaque fonctionnalité :

  1. Flux heureux (happy path)
  2. Validation (données invalides → 422)
  3. Authentification (non connecté → 401)
  4. Autorisation (mauvais rôle → 403)
  5. Cas limites (ressource inexistante → 404)

Pre-commit hooks (Husky)

Ne jamais utiliser --no-verify

Le hook pre-commit exécute automatiquement à chaque commit :

  1. lint-staged — Lint des fichiers modifiés (ESLint + Pint)
  2. TypeScript — Vérification des types (tsc --noEmit)
  3. Build frontend — Vérifie que le build de production passe
  4. PHPStan — Analyse statique PHP niveau 6
  5. Pest — Tests backend + couverture ≥ 80%
  6. Vitest — Tests frontend (conditionnel : ignoré s'il n'y a pas encore de fichiers *.test.ts(x))

Tests frontend conditionnels

Les tests Vitest sont ignorés automatiquement s'il n'y a pas encore de fichiers de test dans frontend/src/. Cela permet de travailler en early-stage sans blocage.