⚙️ Développement

Tests unitaires, débogage et qualité du code

📅 10 avril 202612 min de lecture
testsphpjavapython
Série : Algorithmique et POO

Pourquoi tester ?

Les tests détectent les bugs avant la mise en production, documentent le comportement attendu du code, et permettent de modifier du code existant sans craindre les régressions. Un code sans tests est un code qui se dégrade.

Types de tests

TypeScopeVitesseQui ?
UnitaireUne fonction/méthode isoléeTrès rapideDéveloppeur
IntégrationInteraction entre composants (BDD, API)MoyenDéveloppeur
FonctionnelScénario utilisateur completLentQA / Dev
Non-régressionVérifier que le code modifié ne casse rienVariableCI/CD
PerformanceTemps de réponse, chargeLentOps / Dev

Pyramide des tests

La base est large (beaucoup de tests unitaires, rapides et ciblés), le milieu contient des tests d'intégration (moins nombreux), et le sommet des tests E2E/fonctionnels (peu, lents mais critiques).

Tests boîte noire vs boîte blanche

Boîte noire : on teste le comportement sans connaître l'implémentation. On vérifie que pour une entrée donnée, la sortie est correcte. Approche du testeur/QA.

Boîte blanche : on connaît le code et on teste les chemins internes (branches, boucles, cas limites). Approche du développeur. Permet de mesurer la couverture de code.

Tests unitaires en pratique

Structure d'un test (Arrange-Act-Assert)

# pytest (Python)
def test_calculer_moyenne():
    # Arrange : préparer les données
    notes = [12, 14, 16, 18]
 
    # Act : exécuter la fonction testée
    resultat = calculer_moyenne(notes)
 
    # Assert : vérifier le résultat
    assert resultat == 15.0
// JUnit 5 (Java)
@Test
void testCalculerMoyenne() {
    int[] notes = {12, 14, 16, 18};
    double resultat = calculerMoyenne(notes);
    assertEquals(15.0, resultat, 0.01);
}
// PHPUnit (PHP)
public function testCalculerMoyenne(): void
{
    $notes = [12, 14, 16, 18];
    $resultat = $this->service->calculerMoyenne($notes);
    $this->assertEquals(15.0, $resultat);
}

Cas limites à tester

Toujours tester : la liste vide, un seul élément, les valeurs limites (0, -1, max), les entrées invalides (null, type incorrect), le cas nominal (fonctionnement normal).

Assertions courantes

AssertionVérifie
assertEquals(attendu, résultat)Égalité
assertTrue(condition)Condition vraie
assertNull(valeur)Valeur nulle
assertThrows(Exception.class, () -> ...)Exception levée
assertContains(élément, collection)Présence dans une liste

Mocks et stubs

Quand une classe dépend d'un service externe (BDD, API, email), on la simule pour tester en isolation :

Stub : retourne des valeurs prédéfinies, pas de vérification d'appel.

Mock : simule l'objet ET vérifie que les méthodes attendues ont été appelées avec les bons paramètres.

// PHPUnit — mock du repository
$repo = $this->createMock(ArticleRepository::class);
$repo->method('find')->with(42)->willReturn($articleFictif);
 
$service = new ArticleService($repo);
$result = $service->getArticle(42);
$this->assertEquals('Mon article', $result->getTitle());

Couverture de code

La couverture mesure le pourcentage de code exécuté par les tests. Types : couverture de lignes, de branches (if/else), de fonctions. Un objectif de 80% est courant. Attention : 100% de couverture ne signifie pas zéro bug — la qualité des assertions compte autant.

Débogage

Débogage pas-à-pas

Les IDE modernes (PhpStorm, VS Code, IntelliJ) permettent le débogage interactif : breakpoint (point d'arrêt sur une ligne), step over (exécuter la ligne, passer à la suivante), step into (entrer dans la fonction appelée), step out (sortir de la fonction courante), watch (surveiller la valeur d'une variable en temps réel).

Xdebug (PHP)

; php.ini
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.client_host = host.docker.internal
xdebug.client_port = 9003

Techniques de débogage

  • Logging : console.log, var_dump, print — simple mais polluant
  • Débogueur : breakpoints, inspection — propre et puissant
  • Divide and conquer : commenter la moitié du code pour isoler le problème
  • Rubber duck : expliquer le code à voix haute (ou à un canard en plastique)

Documentation du code

Commentaires et docblocks

/**
 * Calcule la moyenne d'un tableau de notes.
 *
 * @param float[] $notes  Liste de notes (0-20)
 * @return float          Moyenne arrondie à 2 décimales
 * @throws \InvalidArgumentException Si le tableau est vide
 */
public function calculerMoyenne(array $notes): float

Conventions de nommage

ÉlémentConventionExemple
ClassePascalCaseArticleService
Méthode/fonctioncamelCasegetPublishedArticles()
ConstanteUPPER_SNAKEMAX_UPLOAD_SIZE
VariablecamelCase$articleCount
Table BDDsnake_casequiz_sessions

Points clés pour le concours

  • Unitaire = une fonction isolée, Intégration = entre composants
  • Boîte noire = tester le comportement, Boîte blanche = tester les chemins internes
  • Structure Arrange-Act-Assert pour chaque test
  • Toujours tester les cas limites (vide, null, bornes)
  • Mocks pour isoler les dépendances externes
  • Le débogueur pas-à-pas est plus efficace que var_dump