Skip to Content
04 TestingStratégies de Test

Stratégies de Test

Comprendre quand utiliser chaque type de test et comment construire une suite de tests efficace pour l’architecture hexagonale.

La pyramide de tests guide vos décisions : beaucoup de tests unitaires rapides, quelques tests d’intégration, et peu de tests E2E.


La Pyramide de Tests

La Pyramide Classique

/\ / \ E2E Tests (5%) /----\ - Lents (secondes/minutes) / Inte \ - Fragiles / gration\ - Coûteux à maintenir /------------\ / \ Integration Tests (15%) / Unit Tests \ - Moyennement rapides /------------------\- Tests avec dépendances /____________________\ Unit Tests (80%) - Ultra rapides (ms) - Stables - Faciles à maintenir

Principe de base : Plus on monte dans la pyramide, plus les tests sont :

  • Lents à exécuter
  • Fragiles (cassent facilement)
  • Coûteux à maintenir
  • Réalistes (proches de la prod)

Stratégies par Couche

Tests du Domain Layer

Le domain est 100% testable en unitaire car il n’a AUCUNE dépendance externe.

Que Tester ?

Valider les règles métier

@Test void trendResultShouldRejectNegativeValues() { assertThrows(IllegalArgumentException.class, () -> new TrendResult("java", -10, "2025-01-15")); }

Tester les Value Objects

@Test void keywordShouldNormalizeInput() { var keyword = new Keyword(" JAVA "); assertEquals("java", keyword.value()); }

Vérifier l’immutabilité

@Test void trendResultShouldBeImmutable() { var result = new TrendResult("java", 85, "2025-01-15"); // Impossible de modifier les valeurs }

Stratégie Recommandée

  • 100% de couverture sur le domain
  • ✅ Tests unitaires purs (pas de mocks)
  • ✅ AAA pattern (Arrange/Act/Assert)
  • ✅ Tests rapides (ms)

Stratégie Complète pour un Use Case

Voici comment tester un use case complet en suivant la pyramide.

Exemple : GetTrendsUseCase

Tests Unitaires du Domain (80%)

// Tester TrendResult, TrendRequest, règles métier class TrendResultTest { @Test void shouldCreateValidTrendResult() { } @Test void shouldRejectNegativeValue() { } @Test void shouldFormatDateCorrectly() { } }

Objectif : Valider TOUTE la logique métier.

Tests Unitaires de l’Application (80%)

// Tester GetTrendsUseCase avec mocks class GetTrendsUseCaseTest { @Mock TrendRepository mockRepository; @Test void shouldReturnTrends() { } @Test void shouldHandleErrors() { } @Test void shouldValidateInput() { } }

Objectif : Tester l’orchestration sans dépendances.

Tests d’Intégration (15%)

// Tester le flux complet HTTP → Domain @MicronautTest class TrendControllerIntegrationTest { @Inject HttpClient client; @Test void shouldReturnTrendsViaHTTP() { var response = client.toBlocking() .exchange("/api/trends?keyword=java", TrendDto[].class); assertEquals(HttpStatus.OK, response.status()); } }

Objectif : Valider l’intégration complète.

Tests d’Architecture (Bonus)

// Vérifier que l'architecture est respectée @Test void domainShouldNotDependOnInfrastructure() { noClasses().that().resideInPackage("..domain..") .should().dependOnClassesThat() .resideInPackage("..infrastructure..") .check(classes); }

Objectif : Garantir le respect de l’architecture.


Matrice de Décision

Utilisez ce tableau pour décider quel type de test écrire.

Vous Voulez TesterType de TestOutilTemps
Règle métier pure✅ UnitaireJUnit1ms
Validation domain✅ UnitaireJUnit1ms
Use case (orchestration)✅ UnitaireMockito5ms
Controller → Use Case⚠️ Intégration@MicronautTest100ms
Appel HTTP externe⚠️ Intégration@MicronautTest200ms
Conversion JSON ↔ DTO⚠️ IntégrationObjectMapper50ms
Architecture respectée✅ ArchitectureArchUnit10ms
Parcours utilisateur❌ E2ESelenium10s

Anti-Patterns à Éviter

Anti-Pattern : Trop de Mocks

Problème : Mocker dans les tests unitaires du domain.

// ❌ MAUVAIS : Le domain n'a pas de dépendances ! class TrendResultTest { @Mock SomeService mockService; // ❌ Pourquoi ? @Test void test() { // Le domain est pur, pas besoin de mocks } }

Solution :

// ✅ BON : Tests purs sans mocks class TrendResultTest { @Test void shouldCreateTrendResult() { var result = new TrendResult("java", 85, "2025-01-15"); assertEquals("java", result.keyword()); } }

Règle : Si vous mockez dans le domain, c’est que votre domain a des dépendances → architecture incorrecte !


Checklist : Quelle Stratégie pour Votre Projet ?

Commencez par les tests d’architecture

# Installation ArchUnit mvn archunit:check

Pourquoi en premier ? Garantit que l’architecture est respectée dès le début.

Écrivez les tests unitaires du domain

  • ✅ Testez toutes les règles métier
  • ✅ Validez les Value Objects
  • ✅ Vérifiez les invariants

Objectif : 100% de couverture du domain.

Ajoutez les tests unitaires des use cases

  • ✅ Mocker les ports (repositories, services)
  • ✅ Tester l’orchestration
  • ✅ Vérifier la gestion d’erreurs

Objectif : 80%+ de couverture de l’application layer.

Complétez avec des tests d’intégration

  • ⚠️ Tester les adapters (API, BDD)
  • ⚠️ Valider le flux HTTP complet
  • ⚠️ Vérifier la serialisation JSON

Objectif : Cas critiques uniquement (15% du total).

Automatisez dans la CI/CD

# GitHub Actions - name: Run tests run: mvn test

Objectif : Tests exécutés à chaque commit.


Récapitulatif

Une bonne stratégie de test = 80% unitaires, 15% intégration, 5% E2E + tests d’architecture.

Règles d’Or

  1. Domain → 100% tests unitaires purs
  2. Application → Tests unitaires avec mocks
  3. Infrastructure → Tests d’intégration ciblés
  4. Architecture → ArchUnit pour validation automatique

Temps d’Exécution Cible

  • Tests unitaires : < 1 seconde pour toute la suite
  • ⚠️ Tests d’intégration : < 30 secondes
  • Tests d’architecture : < 1 seconde
  • 🎯 Total : < 1 minute pour 200+ tests

Prochaines Étapes

Vous avez maintenant une stratégie complète. Passez à la pratique !

Last updated on