Les types de tests logiciels : le guide complet

Tests unitaires, intégration, E2E, performance, sécurité, accessibilité… Le guide complet des types de tests logiciels, avec objectifs, exemples et outils.

Pyramide des tests logiciels : tests unitaires, intégration et end-to-end

L'essentiel en bref

Les types de tests logiciels désignent les différentes façons de vérifier qu'un logiciel fonctionne correctement, répond aux besoins et résiste aux usages réels. On les classe selon trois grands axes : par niveau (unitaire, intégration, système, acceptation), par objectif (fonctionnel ou non-fonctionnel) et par connaissance du code (boîte blanche ou boîte noire). Aucun type de test ne suffit seul : un logiciel solide combine plusieurs familles selon une stratégie réfléchie, souvent illustrée par la pyramide des tests. Les tests unitaires valident la plus petite brique de code, les tests d'intégration vérifient les échanges entre modules, les tests fonctionnels et end-to-end contrôlent les parcours complets, tandis que les tests de performance, de sécurité, d'accessibilité ou de compatibilité couvrent les exigences non fonctionnelles. Ce guide détaille chaque type de test : sa définition, son objectif, le bon moment pour l'utiliser, un exemple concret et les outils associés. L'enjeu n'est pas de tout tester partout, mais de tester intelligemment ce qui compte vraiment.

  • Trois classifications : par niveau, par objectif (fonctionnel/non-fonctionnel), par accès au code (boîte blanche/noire).
  • Pyramide des tests : beaucoup de tests unitaires, moins d'intégration, peu de tests end-to-end.
  • Fonctionnel : est-ce que ça fait ce que c'est censé faire ?
  • Non-fonctionnel : est-ce rapide, sûr, accessible, compatible, robuste ?
  • Règle d'or : combiner les types selon le risque et la criticité, pas tout tester aveuglément.

Pourquoi parler de types de tests logiciels ?

Tout logiciel non testé est un logiciel dont on ignore le comportement réel. Entre l'intention exprimée par un cahier des charges et le code livré en production, il existe un fossé peuplé de malentendus, d'oublis, d'effets de bord et de cas limites. Les tests logiciels sont les ponts qui permettent de franchir ce fossé en confiance. Mais il n'existe pas un test universel capable de tout couvrir : vérifier qu'une fonction de calcul renvoie le bon résultat n'a rien à voir avec s'assurer qu'une application supporte dix mille utilisateurs simultanés, ou qu'un formulaire reste utilisable par une personne malvoyante. C'est pourquoi le monde du test logiciel s'est structuré en de nombreux types de tests, chacun répondant à une question précise.

Comprendre ces types de tests, ce n'est pas seulement une affaire de jargon pour ingénieurs qualité. C'est un sujet stratégique pour un CTO qui doit arbitrer un budget, pour un product manager qui veut livrer vite sans casser l'existant, pour un développeur qui cherche à dormir tranquille après une mise en production, et bien sûr pour les équipes QA dont c'est le métier. Choisir les bons types de tests, au bon niveau, au bon moment, fait la différence entre un produit qui inspire confiance et un produit qui s'effondre au premier pic de trafic ou à la première mise à jour.

Chez Captain Submit, studio de développement de SaaS et d'applications mobiles, nous considérons la stratégie de test comme une composante de la conception produit, et non comme une formalité de fin de chaîne. Ce guide complet a pour ambition de passer en revue, en profondeur, chaque type de test indispensable : ce qu'il est, à quoi il sert, quand l'utiliser, avec quel exemple concret et quels outils. Pour une vision plus large de la démarche qualité, vous pouvez compléter cette lecture avec notre guide complet du QA et du testing, et pour l'arbitrage entre automatisation et test manuel, notre comparatif tests automatisés vs tests manuels.

Comment classe-t-on les types de tests logiciels ?

Avant de plonger dans chaque type de test, il faut comprendre comment ils s'articulent. Une erreur fréquente consiste à voir les tests comme une liste plate et interminable. En réalité, ils se rangent selon plusieurs axes de classification complémentaires. Un même test peut appartenir à plusieurs catégories à la fois : un test peut être à la fois un test d'intégration (par son niveau), fonctionnel (par son objectif) et boîte noire (par son rapport au code). Maîtriser ces axes permet de raisonner clairement sur sa couverture de test.

La classification par niveau

Le premier axe, le plus structurant, est le niveau auquel on teste. Il répond à la question : sur quelle granularité du système porte la vérification ? On distingue traditionnellement quatre niveaux, du plus fin au plus large.

  • Niveau unitaire : on teste une unité isolée de code, typiquement une fonction, une méthode ou une classe, indépendamment du reste du système.
  • Niveau intégration : on teste la collaboration entre plusieurs unités ou modules, et leurs échanges avec des dépendances comme une base de données ou une API.
  • Niveau système : on teste l'application complète, assemblée, comme un tout cohérent, du point de vue de son comportement global.
  • Niveau acceptation : on vérifie que le système répond aux attentes métier et aux besoins de l'utilisateur final, souvent avec sa participation.

Ces niveaux forment un continuum. Plus on monte, plus on se rapproche de l'expérience réelle de l'utilisateur, mais plus les tests deviennent lents, coûteux et fragiles. Plus on descend, plus les tests sont rapides et stables, mais plus ils s'éloignent de la réalité d'usage. Cette tension est au cœur de la stratégie de test.

La classification par objectif : fonctionnel ou non-fonctionnel

Le deuxième axe distingue ce que l'on cherche à vérifier. Les tests fonctionnels s'intéressent à ce que fait le logiciel : les fonctionnalités, les règles métier, les résultats attendus. La question est binaire dans l'esprit : le système produit-il le bon résultat pour une entrée donnée ? Les tests non-fonctionnels, eux, s'intéressent à comment le logiciel se comporte : sa rapidité, sa robustesse sous charge, sa sécurité, son accessibilité, sa compatibilité, sa consommation de ressources. Un logiciel peut être parfaitement fonctionnel et pourtant inutilisable parce qu'il est trop lent, vulnérable ou inaccessible.

La classification par accès au code : boîte blanche ou boîte noire

Le troisième axe concerne la connaissance que le testeur a du fonctionnement interne. En test boîte blanche (white box), on connaît et on exploite la structure interne du code : on cherche à parcourir tous les chemins logiques, toutes les branches, toutes les conditions. C'est typiquement le domaine des tests unitaires écrits par les développeurs. En test boîte noire (black box), on ignore délibérément l'implémentation : on teste uniquement à travers les entrées et les sorties, comme le ferait un utilisateur. C'est typiquement le domaine des tests fonctionnels et d'acceptation. Entre les deux, le test boîte grise (gray box) combine une connaissance partielle de l'interne, par exemple pour les tests d'intégration ou de sécurité.

Quel est le tableau récapitulatif de tous les types de tests ?

Pour ancrer la suite, voici une vue d'ensemble de tous les types de tests que nous allons détailler. Ce tableau associe à chaque type son objectif principal, son niveau dominant et des exemples d'outils. Gardez-le comme une carte de référence : la suite de l'article approfondit chaque ligne.

Type de test Objectif principal Niveau dominant Exemples d'outils
Tests unitaires Valider une unité de code isolée Unitaire Jest, Vitest, JUnit, pytest, PHPUnit
Tests d'intégration Vérifier les échanges entre modules et dépendances Intégration Testcontainers, Supertest, Spring Test
Tests fonctionnels Confirmer que les fonctionnalités répondent aux specs Système Cypress, Playwright, Selenium
Tests end-to-end (E2E) Valider un parcours utilisateur complet Système Playwright, Cypress, Selenium
Tests de non-régression S'assurer qu'une évolution ne casse pas l'existant Tous niveaux Suite CI, Jest, Playwright
Tests de performance Mesurer rapidité et tenue sous charge Système (non-fonctionnel) k6, JMeter, Gatling, Locust
Tests de sécurité Détecter les vulnérabilités Tous niveaux (non-fonctionnel) OWASP ZAP, Burp Suite, Snyk, SonarQube
Tests d'acceptation (UAT) Valider la conformité au besoin métier Acceptation Cucumber, FitNesse, sessions utilisateurs
Tests de fumée (smoke) Vérifier que le build est exploitable Système Suite CI, Playwright, scripts
Tests sanity Vérifier rapidement une correction ciblée Système Tests manuels ou ciblés
Tests exploratoires Découvrir des défauts non anticipés Système (manuel) Sessions chartées, outils de capture
Tests d'accessibilité Garantir l'usage par tous, y compris en situation de handicap Système (non-fonctionnel) axe, Lighthouse, WAVE, lecteurs d'écran
Tests de compatibilité Vérifier le bon fonctionnement multi-environnements Système (non-fonctionnel) BrowserStack, Sauce Labs, LambdaTest
Tests d'API Valider les contrats et comportements des services Intégration Postman, REST Assured, Supertest, Pact
Tests de mutation Mesurer la qualité réelle des tests existants Unitaire Stryker, PIT, mutmut
Tests de contrat Garantir la compatibilité entre services Intégration Pact, Spring Cloud Contract
Tests visuels Détecter les régressions d'interface Système Percy, Chromatic, Applitools

Qu'est-ce que la pyramide des tests ?

La pyramide des tests est le modèle de référence pour répartir l'effort de test entre les différents niveaux. Formulée à l'origine par Mike Cohn, elle propose une image simple : on construit beaucoup de tests rapides et bon marché à la base, moins de tests intermédiaires au milieu, et très peu de tests lents et coûteux au sommet. La forme pyramidale traduit cette répartition idéale des volumes.

La base de la pyramide est constituée des tests unitaires. Ils sont nombreux car ils sont rapides à exécuter (quelques millisecondes), stables, peu coûteux à écrire et à maintenir, et ils localisent précisément les défauts. Le niveau intermédiaire regroupe les tests d'intégration et les tests d'API : moins nombreux, ils vérifient que les briques collaborent correctement. Le sommet rassemble les tests end-to-end, qui simulent un utilisateur réel naviguant dans l'application complète. Ces derniers sont les plus proches de la réalité, mais aussi les plus lents, les plus fragiles et les plus coûteux à maintenir, d'où leur faible nombre.

La logique économique est limpide. Un bug détecté par un test unitaire coûte quelques secondes à corriger ; le même bug détecté par un test end-to-end demande de remonter toute la chaîne pour localiser la cause ; et s'il échappe à tous les tests pour atterrir en production, son coût explose. Plus un défaut est détecté tôt et bas dans la pyramide, moins il coûte cher. C'est le principe du shift-left : déplacer le test le plus à gauche possible dans le cycle de développement.

Plusieurs anti-modèles guettent les équipes. Le cône de glace, ou pyramide inversée, décrit une situation où l'essentiel des tests sont des tests end-to-end lents et fragiles, avec très peu de tests unitaires : la suite devient lente, instable et décourageante. Le sablier décrit une couche d'intégration atrophiée, avec beaucoup d'unitaires et beaucoup d'E2E mais rien entre les deux. Le trophée des tests, proposé par Kent C. Dodds notamment pour le développement front-end moderne, rééquilibre la pyramide en donnant plus de poids aux tests d'intégration, jugés plus représentatifs du comportement réel dans certains contextes. Retenez l'idée maîtresse : peu importe la forme exacte, il s'agit de placer le bon volume de tests au bon niveau, en privilégiant la rapidité et la stabilité à la base.

Qu'est-ce qu'un test unitaire ?

Définition. Un test unitaire vérifie le comportement de la plus petite unité de code testable de manière isolée : une fonction, une méthode ou une classe. On l'isole de ses dépendances externes (base de données, réseau, fichiers, autres modules) à l'aide de doublures de test comme les mocks, les stubs ou les fakes, afin de ne tester que la logique de l'unité elle-même.

Objectif. Garantir qu'une brique élémentaire de logique produit le résultat attendu pour un ensemble d'entrées, y compris les cas limites et les cas d'erreur. Le test unitaire est l'outil de localisation des défauts par excellence : quand il échoue, vous savez immédiatement quelle fonction est en cause, sans avoir à dérouler tout un parcours.

Quand l'utiliser. En continu, pendant le développement, idéalement écrits en même temps que le code, voire avant lui dans la pratique du TDD (Test Driven Development). Les tests unitaires sont la fondation de toute suite de tests sérieuse et la base de la pyramide. Ils sont indispensables sur la logique métier, les calculs, les transformations de données, les règles de validation et tout code dont la justesse est critique.

Exemple concret. Imaginez une fonction calculerTotalPanier qui prend une liste d'articles avec quantités et prix, applique éventuellement un code promo, et renvoie le montant TTC. Un test unitaire vérifiera : le total d'un panier vide vaut zéro, le total d'un panier simple est correct, une remise de 10 pour cent est bien appliquée, un code promo invalide est ignoré, et un prix négatif lève une erreur. Chacun de ces cas est un test rapide, déterministe, qui s'exécute sans base de données ni serveur.

Outils. En JavaScript et TypeScript : Jest et Vitest. En Java : JUnit avec Mockito. En Python : pytest et unittest. En PHP : PHPUnit. En C# : xUnit, NUnit. En Go : le package testing natif. La plupart de ces frameworks fournissent assertions, doublures de test et mesure de couverture de code.

  • Bonnes pratiques : un test par comportement, des noms explicites décrivant le cas testé, le schéma Arrange-Act-Assert, l'indépendance totale entre tests.
  • Pièges : tester l'implémentation plutôt que le comportement, abuser des mocks au point de tester les mocks eux-mêmes, viser un pourcentage de couverture sans pertinence.

À quoi servent les tests d'intégration ?

Définition. Un test d'intégration vérifie que plusieurs unités, modules ou composants fonctionnent correctement ensemble, ainsi que leurs interactions avec des dépendances réelles ou réalistes : base de données, file de messages, API externe, système de fichiers. Là où le test unitaire isole, le test d'intégration assemble.

Objectif. Détecter les défauts qui n'apparaissent qu'aux frontières entre composants : un format de données mal interprété, une requête SQL incorrecte, une mauvaise gestion d'une réponse d'API, un problème de transaction. Beaucoup de bugs réels naissent non pas dans une fonction isolée, mais dans la façon dont deux modules se parlent.

Quand l'utiliser. Dès qu'un composant interagit avec une dépendance significative : couche d'accès aux données, services externes, intégrations tierces. Ils complètent les tests unitaires et constituent le niveau intermédiaire de la pyramide. Ils sont particulièrement précieux sur les points d'entrée HTTP, les repositories et les services qui orchestrent plusieurs collaborateurs.

Exemple concret. Un endpoint POST /commandes reçoit une requête, valide les données, enregistre une commande en base, décrémente le stock et publie un événement. Un test d'intégration enverra une vraie requête HTTP à l'application démarrée, vérifiera le code de réponse, contrôlera que la commande existe bien en base, que le stock a diminué et qu'un événement a été émis. Ici, on ne moque pas la base : on utilise une base réelle, souvent éphémère via un conteneur.

Outils. Testcontainers pour faire tourner de vraies bases de données ou services en conteneurs jetables pendant les tests, Supertest pour interroger une API Node, Spring Test pour l'écosystème Java, pytest avec des fixtures pour Python. Les bases en mémoire (comme une base SQLite ou H2) sont parfois utilisées, au prix d'une moindre fidélité au moteur de production.

  • Bonnes pratiques : utiliser des dépendances aussi proches que possible de la production, isoler l'état entre tests, nettoyer les données après chaque scénario.
  • Pièges : rendre les tests dépendants de l'ordre d'exécution, laisser des données résiduelles, transformer des tests d'intégration en tests end-to-end déguisés et lents.

Que vérifient les tests fonctionnels ?

Définition. Un test fonctionnel valide qu'une fonctionnalité se comporte conformément à sa spécification, du point de vue de l'utilisateur ou du métier, sans se préoccuper de l'implémentation interne. C'est un test boîte noire : on fournit des entrées, on observe des sorties, et on compare au comportement attendu décrit dans les exigences.

Objectif. Confirmer que le logiciel fait ce qu'il est censé faire. Un test fonctionnel répond à la question : quand l'utilisateur effectue telle action dans telles conditions, obtient-il le résultat prévu ? Il couvre les règles métier, les flux nominaux et les cas d'erreur attendus.

Quand l'utiliser. Pour valider chaque fonctionnalité significative avant sa mise en production, et pour constituer un filet de sécurité réutilisable. Les tests fonctionnels peuvent s'exécuter au niveau de l'API ou au niveau de l'interface graphique. Ils sont au cœur de la validation système.

Exemple concret. Sur une fonctionnalité de connexion, un test fonctionnel vérifiera qu'avec un identifiant et un mot de passe valides l'utilisateur accède à son tableau de bord, qu'avec un mot de passe erroné un message d'erreur s'affiche sans révéler si l'email existe, et qu'après plusieurs échecs le compte est temporairement verrouillé. On teste le comportement observable, pas la fonction de hachage interne.

Outils. Au niveau interface : Cypress, Playwright, Selenium. Au niveau API : Postman, REST Assured, Supertest. Les approches BDD comme Cucumber permettent d'exprimer les tests fonctionnels en langage proche du métier (Étant donné, Quand, Alors).

  • Bonnes pratiques : partir des exigences et des cas d'usage, couvrir le chemin nominal et les principaux cas d'erreur, garder les tests lisibles par un non-développeur.
  • Pièges : tester via l'interface ce qui pourrait l'être plus vite via l'API, multiplier les scénarios redondants, négliger les cas limites.

Qu'est-ce qu'un test end-to-end (E2E) ?

Définition. Un test end-to-end, ou de bout en bout, simule un parcours utilisateur complet à travers l'application entière, dans des conditions aussi proches que possible de la production. Il traverse toutes les couches : interface, services, base de données, parfois services externes. C'est le test le plus haut de la pyramide.

Objectif. Vérifier qu'un scénario métier critique fonctionne de bout en bout, comme le vivrait un vrai utilisateur. Là où les tests unitaires et d'intégration valident des morceaux, l'E2E valide que l'ensemble tient debout une fois assemblé. Il détecte les défauts d'intégration globale invisibles aux niveaux inférieurs.

Quand l'utiliser. Avec parcimonie, sur les parcours les plus critiques pour le business : inscription, connexion, ajout au panier et paiement, création d'un document clé. La règle est de couvrir les happy paths essentiels et quelques scénarios d'erreur majeurs, sans chercher l'exhaustivité, sous peine d'une suite lente et instable.

Exemple concret. Sur un site e-commerce, un test E2E démarre un navigateur, recherche un produit, l'ajoute au panier, renseigne une adresse, saisit des informations de paiement en environnement de test, valide la commande et vérifie l'affichage de la confirmation ainsi que la présence de la commande dans l'espace client. Tout le système est sollicité, de l'interface au paiement.

Outils. Playwright et Cypress dominent l'écosystème web moderne, avec attente automatique des éléments, capture d'écran et exécution multi-navigateurs. Selenium reste très répandu, notamment pour sa large compatibilité. Pour le mobile : Appium, Detox, Espresso et XCUITest.

  • Bonnes pratiques : limiter le nombre d'E2E aux parcours vitaux, rendre les tests indépendants et reproductibles, gérer les données de test de façon déterministe, utiliser des sélecteurs stables.
  • Pièges : les tests instables (flaky) qui échouent aléatoirement et minent la confiance, la dépendance à des données de production, des temps d'exécution qui bloquent la chaîne de livraison.

Pourquoi les tests de non-régression sont-ils indispensables ?

Définition. Un test de non-régression vérifie qu'une modification du code (nouvelle fonctionnalité, correction de bug, refactorisation, mise à jour de dépendance) n'a pas dégradé ou cassé une fonctionnalité qui marchait auparavant. La non-régression n'est pas un type de test à part par sa technique, mais par son intention : réexécuter des tests existants pour protéger l'acquis.

Objectif. Empêcher les régressions, c'est-à-dire l'apparition de défauts dans des zones censées être stables. C'est l'un des risques les plus insidieux du développement logiciel : on corrige un bug ici, on en introduit un autre là-bas. La suite de non-régression est le filet qui attrape ces effets de bord.

Quand l'utiliser. À chaque évolution, idéalement de manière automatisée à chaque commit ou à chaque pull request via l'intégration continue. La non-régression s'appuie sur l'ensemble des tests automatisés (unitaires, intégration, E2E) accumulés au fil du temps. C'est précisément ce qui rend l'automatisation rentable : un test écrit une fois protège indéfiniment.

Exemple concret. Une équipe ajoute une option de paiement fractionné. Avant de fusionner, la chaîne d'intégration rejoue toute la suite : les tests vérifient que le paiement classique fonctionne toujours, que les remises s'appliquent comme avant, que les emails de confirmation partent encore. Si l'un d'eux échoue, la régression est détectée avant la production, pas après.

Outils. Aucun outil spécifique : on réexécute les suites existantes (Jest, Vitest, JUnit, pytest, Playwright, Cypress) au sein d'une chaîne CI comme GitHub Actions, GitLab CI ou Jenkins. Les tests visuels et les tests de mutation complètent la stratégie de non-régression.

  • Bonnes pratiques : ajouter un test de non-régression à chaque bug corrigé pour qu'il ne réapparaisse jamais, automatiser intégralement, paralléliser pour garder une suite rapide.
  • Pièges : laisser la suite gonfler sans la maintenir, tolérer des tests instables, ne lancer la non-régression que manuellement et trop tard.

Comment fonctionnent les tests de performance ?

Définition. Les tests de performance évaluent le comportement non fonctionnel d'un système sous différentes conditions de sollicitation : temps de réponse, débit, consommation de ressources et stabilité. Ce n'est pas un test unique mais une famille de tests, chacun stressant le système d'une manière différente.

Objectif. Répondre à des questions de vitesse et de tenue : combien d'utilisateurs simultanés le système supporte-t-il ? Quel est le temps de réponse au 95e centile sous charge nominale ? À partir de quel seuil le système se dégrade-t-il, et comment ? Tient-il dans la durée sans fuite de mémoire ? Ces tests protègent l'expérience utilisateur et évitent les effondrements en production.

On distingue plusieurs variantes essentielles :

  • Test de charge (load) : on applique une charge attendue, réaliste, et on vérifie que les temps de réponse et le débit restent dans les objectifs. Question : le système tient-il sa charge nominale ?
  • Test de stress : on pousse la charge au-delà des limites prévues jusqu'au point de rupture, pour observer comment le système se dégrade et s'il récupère ensuite. Question : où est la limite, et l'échec est-il gracieux ?
  • Test d'endurance (soak) : on maintient une charge soutenue sur une longue durée (heures, jours) pour détecter les fuites de mémoire, l'épuisement de connexions ou la dégradation progressive. Question : le système tient-il dans le temps ?
  • Test de pic (spike) : on injecte une montée brutale et soudaine de trafic, puis on revient à la normale, pour vérifier la résilience face aux afflux imprévus (lancement, promotion, effet viral). Question : le système encaisse-t-il un afflux soudain ?
  • Test de capacité (scalability) : on augmente progressivement la charge pour cartographier la montée en charge et déterminer le dimensionnement nécessaire. Question : jusqu'où peut-on monter, et avec quelles ressources ?

Quand l'utiliser. Avant tout lancement à fort enjeu, avant un pic de trafic prévisible, après une refonte d'architecture, et de manière récurrente pour surveiller les dérives. Idéalement, on intègre des tests de performance ciblés dans la chaîne de livraison pour détecter tôt les régressions de latence.

Exemple concret. Avant le Black Friday, une plateforme simule 5 000 utilisateurs virtuels parcourant le catalogue et passant commande. Le test de charge confirme que le temps de réponse reste sous 800 millisecondes. Le test de stress monte jusqu'à 20 000 utilisateurs et révèle que la base de données sature à 12 000, ce qui déclenche la mise en place d'un cache et d'une réplication. Le test de pic simule l'ouverture des ventes flash à minuit.

Outils. k6 (scénarios en JavaScript, très apprécié en CI), Apache JMeter (mature, riche en protocoles), Gatling (haute performance, scénarios en Scala ou Java), Locust (en Python). Côté observation, on couple ces outils à des solutions d'APM et de métriques comme Grafana, Prometheus ou Datadog.

  • Bonnes pratiques : définir des objectifs chiffrés (SLA, centiles) avant de tester, tester dans un environnement représentatif, isoler les variables, mesurer aussi côté serveur (CPU, mémoire, base).
  • Pièges : tester sur un environnement non représentatif, se focaliser sur la moyenne en ignorant les centiles élevés, oublier de tester la récupération après surcharge.

En quoi consistent les tests de sécurité ?

Définition. Les tests de sécurité visent à identifier les vulnérabilités, failles et faiblesses d'un système qui pourraient être exploitées pour compromettre la confidentialité, l'intégrité ou la disponibilité des données et des services. C'est une famille non fonctionnelle qui adopte le point de vue de l'attaquant.

Objectif. Trouver les failles avant les attaquants. On y cherche les injections, les défauts d'authentification et de gestion de session, les contrôles d'accès défaillants, l'exposition de données sensibles, les mauvaises configurations, les dépendances vulnérables. Le référentiel OWASP Top 10 sert de boussole pour les risques web les plus courants.

Les principales approches se complètent :

  • SAST (analyse statique) : on analyse le code source sans l'exécuter pour repérer des motifs dangereux. Tôt dans le cycle, intégrable en CI.
  • DAST (analyse dynamique) : on teste l'application en fonctionnement, de l'extérieur, comme un attaquant, pour détecter les vulnérabilités à l'exécution.
  • SCA (analyse des dépendances) : on inventorie les bibliothèques tierces et on les confronte aux bases de vulnérabilités connues (CVE).
  • Test d'intrusion (pentest) : des experts tentent activement de pénétrer le système, en simulant des attaques réelles, souvent en complément des outils automatisés.

Quand l'utiliser. En continu pour l'analyse statique et l'analyse des dépendances (à chaque commit), périodiquement pour l'analyse dynamique, et avant chaque mise en production majeure pour le test d'intrusion. La sécurité doit être intégrée tout au long du cycle, dans une logique DevSecOps, et non plaquée à la fin.

Exemple concret. Sur un formulaire de recherche, un test de sécurité tente d'injecter une requête SQL malicieuse pour vérifier que les requêtes sont bien paramétrées. Sur l'authentification, il vérifie qu'on ne peut pas accéder aux données d'un autre utilisateur en modifiant un identifiant dans l'URL (faille de contrôle d'accès). L'analyse des dépendances signale une bibliothèque obsolète avec une CVE critique à mettre à jour.

Outils. OWASP ZAP et Burp Suite pour l'analyse dynamique, Snyk et Dependabot pour les dépendances, SonarQube et Semgrep pour l'analyse statique, Trivy pour les conteneurs. Le pentest mobilise des experts humains et un arsenal d'outils spécialisés.

  • Bonnes pratiques : automatiser SAST et SCA en CI, suivre l'OWASP Top 10, traiter les secrets et la configuration avec soin, faire auditer régulièrement par des tiers.
  • Pièges : reléguer la sécurité en fin de projet, ignorer les vulnérabilités des dépendances transitives, négliger la gestion des secrets et des permissions.

Qu'est-ce que les tests d'acceptation (UAT) ?

Définition. Les tests d'acceptation, ou UAT (User Acceptance Testing), valident que le logiciel répond aux besoins métier et aux attentes des utilisateurs finaux dans des conditions réelles d'utilisation. Ils se situent au sommet des niveaux de test et constituent souvent la dernière étape avant la mise en production ou la livraison à un client.

Objectif. Confirmer non pas que le logiciel est correct techniquement, mais qu'il est le bon logiciel : celui qui résout effectivement le problème du métier et que l'utilisateur accepte. C'est une validation de pertinence, pas seulement de conformité technique. La distinction est essentielle : un produit peut passer tous les tests techniques et pourtant ne pas convenir au métier.

Quand l'utiliser. En fin de cycle, avant la mise en production, une fois que les tests fonctionnels et système sont passés. L'UAT est typiquement réalisée par des représentants du métier, des utilisateurs clés ou le client, et non par l'équipe technique. On distingue l'acceptation utilisateur (UAT), l'acceptation opérationnelle (l'exploitation est-elle possible : sauvegardes, supervision, restauration), l'acceptation contractuelle et l'acceptation réglementaire.

Exemple concret. Pour un logiciel de gestion de congés, une responsable RH suit un scénario réel : elle soumet une demande, la fait valider par un manager, vérifie le décompte des jours, exporte un rapport mensuel et confirme que tout correspond à ses processus internes. Si le décompte ne respecte pas la convention collective, le logiciel échoue à l'acceptation, même si le code est techniquement irréprochable.

Outils. Les approches BDD avec Cucumber, SpecFlow ou FitNesse permettent d'écrire des critères d'acceptation lisibles par le métier et exécutables. Mais une large part de l'UAT reste manuelle, structurée par des scénarios et des critères d'acceptation définis avec les parties prenantes.

  • Bonnes pratiques : définir les critères d'acceptation dès la rédaction des besoins, impliquer de vrais utilisateurs, tester sur des données réalistes, documenter les décisions de validation.
  • Pièges : confondre UAT et tests système, lancer l'UAT sans critères clairs, la transformer en chasse aux bugs techniques de dernière minute.

Quelle différence entre tests de fumée (smoke) et tests sanity ?

Ces deux types de tests sont souvent confondus car ils partagent une logique de vérification rapide, mais leur intention diffère.

Tests de fumée (smoke). Le test de fumée est un ensemble réduit de tests qui vérifient que les fonctionnalités les plus critiques d'un build fonctionnent, juste après son déploiement. Le nom vient du matériel électronique : on branche, et si ça fume, inutile d'aller plus loin. L'objectif est de répondre à une question binaire : ce build est-il suffisamment stable pour mériter qu'on lui consacre des tests plus poussés ? On vérifie par exemple que l'application démarre, que la connexion fonctionne, que la page d'accueil se charge, que l'API répond. Si le test de fumée échoue, on rejette le build sans perdre de temps. On l'exécute après chaque nouveau déploiement, en tout début de campagne de test, et systématiquement en CI.

Tests sanity. Le test sanity est une vérification rapide et ciblée, réalisée après une correction de bug ou une petite modification, pour confirmer que le problème précis est résolu et que la zone touchée se comporte rationnellement, avant d'engager une campagne plus complète. C'est un sous-ensemble du test de non-régression, plus étroit et plus profond sur une zone précise. On l'utilise par exemple après le correctif d'un calcul de TVA : on vérifie quelques cas autour de ce calcul, sans relancer toute la suite, pour décider si une vérification approfondie a du sens.

Critère Test de fumée (smoke) Test sanity
Portée Large mais superficielle (fonctions critiques) Étroite mais ciblée (zone modifiée)
Moment Après chaque nouveau build Après une correction ou un petit changement
Question posée Le build est-il exploitable ? La correction tient-elle la route ?
Documentation Souvent scriptée et automatisée Souvent ad hoc, peu documentée
Décision Accepter ou rejeter le build Continuer ou non vers des tests complets

Outils. Les deux s'appuient sur les frameworks existants (Playwright, Cypress, scripts d'API) et sur la CI. Le test de fumée est un excellent candidat à l'automatisation systématique ; le test sanity reste souvent manuel et opportuniste.

À quoi servent les tests exploratoires ?

Définition. Le test exploratoire est une approche où le testeur conçoit et exécute les tests simultanément, en explorant l'application de manière intelligente et créative, sans script prédéfini. Il s'appuie sur son expérience, son intuition et sa compréhension du domaine pour découvrir des défauts que des tests scriptés ne révéleraient jamais.

Objectif. Trouver l'inattendu. Les tests scriptés ne vérifient que ce qu'on a pensé à vérifier ; les tests exploratoires partent à la chasse aux problèmes hors des sentiers battus : enchaînements inhabituels, données surprenantes, manipulations rapides, retours en arrière, comportements à la limite de la spécification. C'est un complément humain indispensable à l'automatisation.

Quand l'utiliser. Sur les nouvelles fonctionnalités, sur les zones à risque, lorsque la spécification est incomplète, ou pour challenger un produit avant un lancement. Une pratique structurée est le session-based testing : on définit une charte (un objectif d'exploration), on explore pendant une durée bornée, puis on consigne les observations.

Exemple concret. Un testeur explore une nouvelle messagerie : il envoie un message très long, colle des émojis et du code, coupe le réseau au milieu de l'envoi, ouvre deux onglets en parallèle, supprime un message pendant qu'un autre se charge. Il découvre ainsi qu'une perte réseau en cours d'envoi duplique le message, un bug qu'aucun scénario formel n'avait prévu.

Outils. Des outils de capture et d'annotation de session, des enregistreurs d'écran, des outils de prise de notes structurées. L'essentiel reste la compétence et la curiosité du testeur ; l'outillage ne fait qu'amplifier sa capacité à documenter ce qu'il découvre.

  • Bonnes pratiques : structurer par chartes et sessions limitées dans le temps, varier les profils de testeurs, consigner systématiquement les découvertes, transformer les bugs trouvés en tests automatisés de non-régression.
  • Pièges : croire que l'exploratoire remplace les tests automatisés, ne pas documenter les sessions, le réserver à un seul expert isolé.

Pourquoi tester l'accessibilité ?

Définition. Les tests d'accessibilité vérifient qu'un logiciel peut être utilisé par tout le monde, y compris les personnes en situation de handicap : visuel, auditif, moteur ou cognitif. Ils s'appuient sur des référentiels comme les WCAG (Web Content Accessibility Guidelines) et, en France, le RGAA (Référentiel Général d'Amélioration de l'Accessibilité).

Objectif. Garantir l'égalité d'accès. Concrètement : une personne aveugle doit pouvoir naviguer au lecteur d'écran, une personne malvoyante doit bénéficier de contrastes suffisants, une personne ne pouvant utiliser de souris doit pouvoir tout faire au clavier, et le contenu doit rester compréhensible. Au-delà de l'éthique, l'accessibilité est une obligation légale dans de nombreux contextes et un levier de qualité globale.

Quand l'utiliser. Dès la conception (couleurs, contrastes, structure), puis tout au long du développement et avant chaque livraison. Une partie peut s'automatiser et s'intégrer en CI, mais l'accessibilité ne se résume pas à un score : seuls des tests manuels avec de vraies technologies d'assistance révèlent les vrais blocages.

Exemple concret. Sur un formulaire, un test d'accessibilité vérifie que chaque champ a une étiquette correctement associée, que les messages d'erreur sont annoncés au lecteur d'écran, que l'ordre de tabulation est logique, que le contraste du texte respecte le ratio minimal, et que l'envoi est possible entièrement au clavier. Un test manuel au lecteur d'écran NVDA confirme que le parcours reste compréhensible sans la vue.

Outils. axe-core et son extension axe DevTools, Lighthouse, WAVE, Pa11y pour l'automatisation ; les lecteurs d'écran NVDA, JAWS et VoiceOver pour les tests manuels. Aucun outil automatique ne couvre plus d'une fraction des critères : le jugement humain reste central.

  • Bonnes pratiques : intégrer l'accessibilité dès le design, utiliser du HTML sémantique et les attributs ARIA à bon escient, tester au clavier et au lecteur d'écran, impliquer des utilisateurs concernés.
  • Pièges : se fier uniquement à un score automatisé, ajouter des attributs ARIA superflus, traiter l'accessibilité comme une retouche finale.

Comment vérifier la compatibilité et le cross-browser ?

Définition. Les tests de compatibilité vérifient que le logiciel fonctionne correctement dans la diversité des environnements cibles : différents navigateurs, versions, systèmes d'exploitation, tailles d'écran, appareils, résolutions et conditions réseau. Pour le web, on parle souvent de tests cross-browser ; pour le mobile, de tests sur parc d'appareils.

Objectif. S'assurer que l'expérience reste correcte quel que soit le contexte de l'utilisateur. Un site peut être parfait sur le navigateur du développeur et défaillant sur un autre, ou illisible sur un petit écran. La fragmentation des navigateurs et des appareils rend ce risque permanent.

Quand l'utiliser. Avant les mises en production significatives, après les évolutions d'interface, et en surveillance régulière selon les statistiques d'usage réelles de votre audience. On priorise les environnements les plus utilisés par vos visiteurs plutôt que de viser une exhaustivité illusoire.

Exemple concret. Une application est testée sur Chrome, Firefox, Safari et Edge, sur Windows et macOS, ainsi que sur iPhone et un appareil Android, en orientation portrait et paysage. On découvre qu'un sélecteur de date s'affiche mal sur Safari iOS et qu'une animation sature un appareil Android d'entrée de gamme : deux défauts invisibles sur l'environnement de développement.

Outils. BrowserStack, Sauce Labs et LambdaTest offrent des parcs de navigateurs et d'appareils réels dans le cloud. Playwright permet d'exécuter des tests sur les principaux moteurs (Chromium, Firefox, WebKit). Pour le responsive, les outils intégrés aux navigateurs et les tests visuels complètent le dispositif.

  • Bonnes pratiques : définir une matrice de compatibilité fondée sur les données d'audience, tester sur de vrais appareils pour les cas critiques, automatiser les vérifications multi-moteurs.
  • Pièges : tester uniquement sur l'environnement du développeur, négliger les appareils mobiles modestes, ignorer les conditions réseau dégradées.

Que valident les tests d'API ?

Définition. Les tests d'API vérifient le comportement des interfaces de programmation (REST, GraphQL, gRPC) directement au niveau du service, sans passer par l'interface graphique. Ils contrôlent les requêtes, les réponses, les codes de statut, les schémas de données, la gestion d'erreurs, l'authentification et les performances de chaque endpoint.

Objectif. Valider la logique métier exposée par les services de façon rapide et stable, à un niveau inférieur à l'interface. Tester via l'API est bien plus rapide et fiable que via l'interface, ce qui en fait un excellent point d'appui pour couvrir un grand nombre de cas fonctionnels sans la fragilité des tests d'interface.

Quand l'utiliser. Systématiquement pour toute application qui expose ou consomme des API, et particulièrement dans les architectures à services multiples ou microservices. Les tests d'API constituent une couche médiane efficace de la pyramide, et le socle des tests d'intégration backend.

Exemple concret. Pour une API de gestion d'utilisateurs, on teste que POST /users avec des données valides renvoie 201 et l'utilisateur créé, que des données invalides renvoient 400 avec un message clair, que GET /users/{id} renvoie 404 pour un identifiant inexistant, qu'une requête sans jeton renvoie 401, et que la pagination et le tri se comportent correctement. On vérifie aussi que la réponse respecte le schéma attendu.

Outils. Postman et sa version automatisée Newman, REST Assured (Java), Supertest (Node), Karate, et les outils de spécification comme OpenAPI pour valider les schémas. Pour les contrats entre services, Pact (voir la section sur les tests de contrat).

  • Bonnes pratiques : tester les cas nominaux, d'erreur et limites, valider les schémas de réponse, couvrir l'authentification et les autorisations, versionner les tests avec l'API.
  • Pièges : ne tester que le happy path, négliger les codes d'erreur, coupler les tests à des données instables.

Qu'est-ce qu'un test de mutation et pourquoi compte-t-il ?

Définition. Le test de mutation est une technique qui évalue la qualité réelle de vos tests, et non celle de votre code. Le principe : un outil introduit volontairement de petites altérations dans votre code source (les mutants), par exemple en remplaçant un plus par un moins, un supérieur par un inférieur, un vrai par un faux. Puis il relance votre suite de tests. Si un test échoue, le mutant est tué : vos tests détectent bien la modification. Si tous les tests passent malgré la mutation, le mutant survit : cela signifie que cette portion de logique n'est pas réellement protégée.

Objectif. Mesurer l'efficacité des tests plutôt que leur simple couverture. Une couverture de 90 pour cent peut masquer des tests qui exécutent le code sans rien vérifier de pertinent. Le score de mutation, lui, indique quelle proportion de défauts introduits vos tests détectent réellement. C'est un indicateur de qualité bien plus honnête que le pourcentage de lignes couvertes.

Quand l'utiliser. Sur le code critique, là où la justesse compte vraiment (calculs financiers, règles métier sensibles, algorithmes). Le test de mutation est coûteux en temps de calcul, on le réserve donc aux zones à fort enjeu et on l'exécute périodiquement plutôt qu'à chaque commit.

Exemple concret. Une fonction applique une remise si le montant dépasse 100 euros. L'outil de mutation remplace la condition montant supérieur à 100 par montant supérieur ou égal à 100. Si aucun test n'utilise précisément la valeur 100, le mutant survit : on découvre qu'un cas limite décisif n'est pas couvert. On ajoute alors un test au seuil exact.

Outils. Stryker (JavaScript, TypeScript, C#, Scala), PIT (Java), mutmut et Cosmic Ray (Python), Infection (PHP). Ces outils produisent un rapport listant les mutants survivants à traiter.

  • Bonnes pratiques : cibler les modules critiques, traiter les mutants survivants comme des trous de couverture, intégrer le test de mutation de façon périodique.
  • Pièges : vouloir un score parfait partout, ignorer le coût en temps de calcul, confondre mutants équivalents (inoffensifs) et vrais trous.

À quoi servent les tests de contrat ?

Définition. Les tests de contrat vérifient que deux services qui communiquent (un consommateur et un fournisseur) respectent un accord commun sur le format des échanges : structure des requêtes et des réponses, champs obligatoires, types. Ils sont au cœur des architectures distribuées et microservices, où des équipes différentes font évoluer des services interdépendants.

Objectif. Détecter au plus tôt les ruptures de compatibilité entre services, sans avoir à déployer et tester l'ensemble du système ensemble. Dans le test de contrat orienté consommateur (consumer-driven), c'est le consommateur qui définit ses attentes ; le fournisseur vérifie ensuite qu'il les honore. Si le fournisseur modifie une réponse de façon incompatible, son test de contrat échoue avant que la casse n'atteigne le consommateur.

Quand l'utiliser. Dès qu'il existe plusieurs services développés et déployés indépendamment, ou des intégrations avec des partenaires externes. Les tests de contrat offrent une alternative bien plus légère et rapide que des tests end-to-end couvrant tous les services à la fois.

Exemple concret. Un service de facturation consomme l'API du service de catalogue pour obtenir le prix d'un produit. Le contrat stipule que la réponse contient un champ prix de type nombre et une devise. Si l'équipe catalogue renomme prix en montant, le test de contrat du fournisseur échoue immédiatement, signalant la rupture avant tout déploiement, là où un test classique ne l'aurait vue qu'en environnement intégré.

Outils. Pact, leader du test de contrat orienté consommateur, avec son broker pour partager les contrats entre équipes ; Spring Cloud Contract dans l'écosystème Java. Ces outils génèrent et vérifient automatiquement les contrats.

  • Bonnes pratiques : faire piloter le contrat par le consommateur, partager les contrats via un broker, vérifier les contrats dans la CI de chaque service.
  • Pièges : confondre tests de contrat et tests fonctionnels du fournisseur, négliger la gestion des versions, oublier de vérifier le contrat côté fournisseur.

Comment fonctionnent les tests visuels ?

Définition. Les tests visuels, ou tests de régression visuelle, détectent les changements involontaires de l'apparence d'une interface en comparant des captures d'écran de référence à de nouvelles captures. Là où un test fonctionnel vérifie qu'un bouton fonctionne, le test visuel vérifie qu'il a toujours la bonne couleur, la bonne position et la bonne taille.

Objectif. Attraper les régressions d'interface qui échappent aux tests fonctionnels : un décalage de mise en page, une couleur modifiée par mégarde, un composant qui déborde, une police cassée. Ces défauts n'empêchent pas le code de fonctionner, mais dégradent l'expérience et la crédibilité du produit.

Quand l'utiliser. Sur les composants d'interface et les pages clés, particulièrement dans les design systems et les bibliothèques de composants partagées, où une modification peut se répercuter partout. On les intègre en CI pour qu'aucun changement visuel ne passe inaperçu.

Exemple concret. Une équipe modifie l'espacement global d'un bouton dans le design system. Le test visuel compare les captures avant et après sur des dizaines de composants et signale qu'un encart de notification, qui réutilisait ce bouton, déborde désormais de son conteneur. Le réviseur valide ou rejette le changement visuel en connaissance de cause.

Outils. Percy, Chromatic (intégré à Storybook), Applitools (avec comparaison assistée par IA pour limiter les faux positifs), et les comparaisons de captures intégrées à Playwright. Ces outils proposent une revue des différences visuelles avant validation.

  • Bonnes pratiques : stabiliser les données et les animations avant capture, réviser et approuver les changements visuels intentionnels, couvrir plusieurs tailles d'écran.
  • Pièges : les faux positifs liés aux polices, animations et contenus dynamiques, l'approbation aveugle des différences, des captures non déterministes.

Tests fonctionnels ou non-fonctionnels : quelle différence concrète ?

Cette distinction structure toute stratégie de test. Les tests fonctionnels répondent à la question est-ce que ça marche comme prévu, les tests non-fonctionnels à la question est-ce que ça marche bien. Un produit doit réussir les deux : une fonctionnalité parfaite mais lente, vulnérable ou inaccessible est un échec. Le tableau suivant clarifie l'opposition et range chaque type de test du guide dans sa famille.

Aspect Tests fonctionnels Tests non-fonctionnels
Question centrale Le système fait-il ce qu'il doit faire ? Le système se comporte-t-il bien ?
Objet vérifié Fonctionnalités, règles métier, résultats Performance, sécurité, accessibilité, robustesse
Critère de succès Résultat conforme à la spécification Respect de seuils de qualité (latence, vulnérabilités)
Exemples de types Unitaire, intégration, fonctionnel, E2E, acceptation, fumée, sanity, API Performance (charge, stress, endurance, pic), sécurité, accessibilité, compatibilité
Détecté trop tard, le défaut donne Une fonctionnalité incorrecte Un effondrement sous charge, une faille, une exclusion d'utilisateurs

Les tests exploratoires, de mutation, de contrat et visuels sont des cas particuliers. L'exploratoire est transversal et plutôt fonctionnel dans l'esprit ; la mutation porte sur la qualité des tests eux-mêmes ; le contrat est une forme spécialisée de test d'intégration ; le visuel relève de la qualité d'interface, à la frontière du fonctionnel et du non-fonctionnel.

Une erreur classique consiste à confondre le niveau d'un test et son objectif. Un test peut être de niveau système et pourtant non-fonctionnel : c'est le cas d'un test de charge qui sollicite l'application entière pour en mesurer la latence. À l'inverse, un test unitaire est presque toujours fonctionnel, car il vérifie le résultat d'une logique précise. Garder ces deux dimensions distinctes dans son raisonnement évite bien des malentendus dans la planification d'une campagne de test. On peut résumer ainsi : le niveau dit où l'on teste, l'objectif dit ce que l'on cherche à prouver, et l'accès au code dit comment on s'y prend.

Et la boîte blanche par rapport à la boîte noire, concrètement ?

La distinction entre boîte blanche et boîte noire n'est pas qu'une question théorique : elle détermine qui écrit le test et ce qu'il peut couvrir. En boîte blanche, le testeur lit le code et conçoit ses cas pour parcourir chaque branche conditionnelle, chaque boucle, chaque chemin d'exécution. C'est la seule façon de garantir qu'une condition complexe est entièrement éprouvée. Les développeurs pratiquent naturellement la boîte blanche sur leurs tests unitaires, car ils connaissent l'intérieur de la fonction qu'ils écrivent.

En boîte noire, le testeur ignore volontairement l'implémentation et raisonne uniquement en termes de comportement attendu. Cette posture est précieuse car elle reproduit la perspective de l'utilisateur et ne se laisse pas piéger par les hypothèses du développeur. Des techniques formelles aident à choisir les cas pertinents en boîte noire : le partitionnement en classes d'équivalence (regrouper les entrées qui devraient se comporter pareil), l'analyse des valeurs limites (tester juste autour des seuils, là où nichent la plupart des bugs), et les tables de décision (couvrir systématiquement les combinaisons de conditions). La boîte grise, enfin, combine les deux : un testeur de sécurité connaissant l'architecture sans avoir le code complet en est un bon exemple.

Comment combiner les types de tests selon le projet ?

Il n'existe pas de combinaison universelle : la bonne stratégie dépend de la nature du produit, de sa criticité, de son stade de maturité et des ressources de l'équipe. Le principe directeur reste constant : investir l'effort de test là où le risque est le plus élevé. Voici comment raisonner selon le contexte.

Pour un MVP ou un produit en phase de découverte

Au stade du MVP, la priorité est d'apprendre vite sans sacrifier la confiance minimale. On privilégie : des tests unitaires sur la logique métier critique, quelques tests d'intégration sur les points d'entrée clés, une poignée de tests end-to-end sur le parcours vital (par exemple inscription et action de valeur principale), et beaucoup de tests exploratoires manuels. On évite de sur-investir dans une suite massive avant d'avoir validé le marché. Pour cadrer ce dosage, notre article sur le MVP aide à distinguer ce qui mérite d'être solidifié de ce qui reste exploratoire.

Pour un SaaS en croissance

Quand le produit gagne des clients, le coût d'une régression augmente fortement. On bâtit alors une pyramide complète : socle solide de tests unitaires, couche d'intégration et d'API étoffée, tests end-to-end ciblés sur les parcours payants, automatisation de la non-régression en CI, premiers tests de performance et de sécurité réguliers, et tests d'accessibilité et de compatibilité selon l'audience. La non-régression automatisée devient le pilier qui permet de livrer souvent sans casser.

Pour une application mobile

Le mobile ajoute la contrainte de la fragmentation des appareils et des systèmes. On combine tests unitaires, tests d'intégration, tests E2E mobiles (Detox, Appium, Espresso, XCUITest), tests de compatibilité sur un parc d'appareils représentatif, et une attention particulière à la performance sur les appareils modestes et aux conditions réseau dégradées.

Pour un système critique ou réglementé

Santé, finance, secteur public : la criticité impose une rigueur maximale. On y ajoute du test de mutation sur le code sensible, des tests de sécurité approfondis et des pentests réguliers, une traçabilité complète entre exigences et tests, et une acceptation formelle documentée. Le coût d'un défaut justifie un investissement de test bien supérieur.

Une heuristique simple

  1. Identifiez les parcours dont l'échec coûterait le plus cher (argent, réputation, conformité).
  2. Couvrez leur logique au niveau unitaire et intégration en priorité, car c'est rapide et stable.
  3. Ajoutez quelques E2E sur ces parcours seulement.
  4. Activez la non-régression automatisée pour protéger l'acquis.
  5. Greffez les tests non-fonctionnels (performance, sécurité, accessibilité, compatibilité) selon les exigences réelles.
  6. Réservez l'exploratoire pour traquer l'inattendu sur les nouveautés.

Besoin d'aide pour bâtir une stratégie de test adaptée à votre produit et à votre budget ? Parlez-en à Captain Submit : nous concevons des SaaS et des applications mobiles avec une démarche qualité intégrée dès la conception.

Comment intégrer les tests dans la chaîne de livraison continue ?

Disposer de bons tests ne suffit pas : encore faut-il les exécuter au bon moment et de la bonne manière. C'est le rôle de l'intégration continue et de la livraison continue, le socle technique qui transforme une collection de tests en véritable filet de sécurité automatique. L'idée centrale est de rejouer automatiquement les tests pertinents à chaque modification du code, avant qu'elle n'atteigne la branche principale ou la production.

Un pipeline typique enchaîne plusieurs étapes, du plus rapide au plus lent, pour donner un retour précoce sans tout faire tourner à chaque fois. On exécute d'abord l'analyse statique et les tests unitaires, qui répondent en quelques secondes ou minutes. Si tout passe, on lance les tests d'intégration et d'API, plus lents car ils mobilisent des bases de données et des services. Viennent ensuite les tests de bout en bout sur les parcours critiques, puis, selon les besoins, les tests de performance, de sécurité, d'accessibilité et visuels, souvent déclenchés moins fréquemment ou sur des branches dédiées.

Cette gradation respecte le principe du retour rapide : un développeur qui casse un test unitaire l'apprend en quelques minutes, tandis que les vérifications lourdes ne s'exécutent que lorsque les fondations sont saines. On parle de fail fast : échouer vite et tôt coûte beaucoup moins cher qu'échouer tard et en production.

  • Parallélisation : répartir les tests sur plusieurs exécuteurs pour garder une durée totale acceptable malgré une suite qui grandit.
  • Quality gates : bloquer la fusion si la couverture, le score de sécurité ou un test critique ne passe pas le seuil défini.
  • Environnements éphémères : recréer à chaque exécution un environnement propre et reproductible, idéalement en conteneurs.
  • Gestion des tests instables : isoler et réparer sans délai les tests flaky qui minent la confiance dans le pipeline.
  • Observabilité : conserver l'historique des exécutions pour repérer les régressions de durée et les tendances d'échec.

Les outils courants sont GitHub Actions, GitLab CI, Jenkins, CircleCI ou Azure Pipelines. Le choix importe moins que la discipline : un pipeline qui rejoue systématiquement les bons tests, donne un retour rapide et bloque ce qui doit l'être vaut mieux que la suite la plus exhaustive jamais exécutée automatiquement.

Comment écrire de bons tests, quel que soit leur type ?

Au-delà des spécificités de chaque famille, certaines qualités caractérisent un bon test, quel que soit son niveau. Un acronyme anglo-saxon les résume : FIRST. Un bon test est Fast (rapide, pour être exécuté souvent sans frein), Isolated ou Independent (indépendant des autres et de l'ordre d'exécution), Repeatable (reproductible, donnant toujours le même résultat dans le même contexte), Self-validating (auto-validant, avec un verdict clair réussite ou échec sans interprétation manuelle) et Timely (écrit au bon moment, idéalement au plus près du code qu'il vérifie).

Un autre principe directeur est de tester le comportement plutôt que l'implémentation. Un test couplé aux détails internes se brise à la moindre refactorisation, même quand le comportement reste correct ; il devient alors un frein au changement plutôt qu'un soutien. Un test orienté comportement, lui, continue de protéger l'acquis tout en laissant le code évoluer librement. C'est l'une des distinctions les plus importantes entre une suite de tests qui accélère une équipe et une suite qui la ralentit.

Enfin, un bon test est lisible. Son nom décrit le cas vérifié, sa structure suit le schéma préparer, agir, vérifier, et un développeur qui le lit comprend immédiatement l'intention. Les tests sont aussi une documentation vivante du comportement attendu du système : bien écrits, ils expliquent ce que le logiciel est censé faire mieux que bien des spécifications. Chez Captain Submit, nous traitons les tests comme du code de première classe, soumis aux mêmes exigences de revue et de soin que le code de production.

Quelles sont les idées reçues et erreurs fréquentes sur les tests ?

Le test logiciel est un domaine truffé de croyances tenaces qui mènent à de mauvais arbitrages. Voici les plus répandues, et ce qu'il faut leur opposer.

  • Idée reçue : 100 pour cent de couverture garantit un logiciel sans bug. Faux. La couverture mesure le code exécuté par les tests, pas la pertinence des vérifications. Un test peut parcourir une fonction sans rien affirmer d'utile. Le test de mutation révèle cette illusion. Visez la pertinence, pas un chiffre.
  • Idée reçue : les tests, c'est uniquement le travail des QA. Faux. La qualité est une responsabilité partagée. Les développeurs écrivent les tests unitaires et d'intégration, les QA conçoivent les stratégies et l'exploratoire, le métier valide l'acceptation. Le silo qualité-développement est contre-productif.
  • Idée reçue : tout automatiser est toujours la bonne approche. Faux. L'automatisation excelle sur la non-régression répétitive et stable, mais l'exploratoire, l'ergonomie et l'acceptation métier réclament l'humain. Notre comparatif tests automatisés vs tests manuels détaille cet arbitrage.
  • Idée reçue : on teste à la fin, juste avant la livraison. Faux et coûteux. Plus un défaut est détecté tard, plus il coûte cher. Le shift-left consiste à tester tôt et en continu, dès l'écriture du code.
  • Idée reçue : beaucoup de tests end-to-end valent mieux que peu. Faux. Une suite dominée par des E2E lents et fragiles (le cône de glace) devient ingérable. Mieux vaut une base solide de tests rapides et quelques E2E ciblés.
  • Idée reçue : un test qui échoue parfois, ce n'est pas grave. Faux. Les tests instables (flaky) détruisent la confiance dans la suite : on finit par ignorer les échecs, y compris les vrais. Un test instable doit être réparé ou supprimé.
  • Idée reçue : les tests ralentissent la livraison. Faux à moyen terme. Sans filet, chaque changement devient risqué et la peur de casser fige le produit. Une bonne suite de tests accélère la livraison en permettant de modifier en confiance.
  • Idée reçue : la performance et la sécurité se vérifient une fois pour toutes. Faux. Ces aspects se dégradent au fil des évolutions et des dépendances. Ils exigent une vérification récurrente.

Points clés à retenir

  • Les types de tests se classent selon trois axes : niveau (unitaire, intégration, système, acceptation), objectif (fonctionnel ou non-fonctionnel) et accès au code (boîte blanche, noire ou grise).
  • La pyramide des tests recommande beaucoup d'unitaires, moins d'intégration et peu d'end-to-end, pour une suite rapide, stable et bon marché.
  • Les tests fonctionnels valident ce que fait le logiciel ; les tests non-fonctionnels (performance, sécurité, accessibilité, compatibilité) valident comment il le fait.
  • Les tests de performance se déclinent en charge, stress, endurance, pic et capacité, chacun répondant à une question distincte.
  • Les tests de sécurité combinent analyse statique, analyse dynamique, analyse des dépendances et tests d'intrusion, dans une logique continue.
  • La non-régression automatisée en CI est le filet qui permet de livrer souvent sans casser l'existant.
  • Le test de mutation mesure la qualité réelle des tests, là où la couverture ne mesure que le code exécuté.
  • La bonne stratégie ne consiste pas à tout tester partout, mais à investir l'effort là où le risque est le plus élevé.
  • La qualité est une responsabilité partagée entre développeurs, QA et métier, dès la conception (shift-left).
  • L'accessibilité et la compatibilité ne sont pas optionnelles : elles conditionnent l'usage réel par toute l'audience.

Questions fréquentes

Quels sont les principaux types de tests logiciels ?

Les principaux types de tests logiciels sont les tests unitaires, les tests d'intégration, les tests fonctionnels, les tests end-to-end, les tests de non-régression, les tests de performance (charge, stress, endurance, pic), les tests de sécurité, les tests d'acceptation, les tests de fumée et sanity, les tests exploratoires, les tests d'accessibilité, les tests de compatibilité, les tests d'API, les tests de mutation, les tests de contrat et les tests visuels. On les classe par niveau (unitaire, intégration, système, acceptation), par objectif (fonctionnel ou non-fonctionnel) et par accès au code (boîte blanche, noire ou grise).

Quelle est la différence entre un test unitaire et un test d'intégration ?

Un test unitaire vérifie une unité de code isolée, comme une fonction ou une classe, en simulant ses dépendances par des mocks ou des stubs. Il est rapide, stable et localise précisément les défauts. Un test d'intégration vérifie au contraire que plusieurs modules collaborent correctement, ainsi que leurs échanges avec des dépendances réelles comme une base de données ou une API. L'unitaire isole, l'intégration assemble. Les deux sont complémentaires et occupent des niveaux différents de la pyramide des tests.

Qu'est-ce que la pyramide des tests ?

La pyramide des tests est un modèle qui recommande de répartir l'effort de test entre les niveaux : beaucoup de tests unitaires à la base car ils sont rapides et bon marché, moins de tests d'intégration au milieu, et peu de tests end-to-end au sommet car ils sont lents, fragiles et coûteux. L'objectif est d'obtenir une suite rapide, stable et économique, tout en détectant les défauts au plus tôt. L'inverse, une suite dominée par les tests end-to-end, est un anti-modèle appelé cône de glace.

Quelle est la différence entre tests fonctionnels et non-fonctionnels ?

Les tests fonctionnels vérifient que le logiciel fait ce qu'il est censé faire : ils contrôlent les fonctionnalités, les règles métier et les résultats attendus. Les tests non-fonctionnels vérifient comment le logiciel se comporte : sa rapidité, sa robustesse sous charge, sa sécurité, son accessibilité et sa compatibilité. Un logiciel peut être parfaitement fonctionnel mais inutilisable parce qu'il est trop lent, vulnérable ou inaccessible, d'où la nécessité de couvrir les deux familles.

Quels sont les différents types de tests de performance ?

On distingue cinq grandes variantes. Le test de charge applique une charge réaliste attendue pour vérifier les temps de réponse. Le test de stress pousse au-delà des limites jusqu'au point de rupture. Le test d'endurance maintient une charge soutenue dans la durée pour détecter les fuites de mémoire. Le test de pic injecte une montée brutale et soudaine de trafic. Le test de capacité augmente progressivement la charge pour déterminer le dimensionnement nécessaire. Chacun répond à une question différente sur la tenue du système.

Qu'est-ce qu'un test end-to-end (E2E) ?

Un test end-to-end simule un parcours utilisateur complet à travers l'application entière, de l'interface jusqu'à la base de données, dans des conditions proches de la production. Il vérifie qu'un scénario métier critique fonctionne de bout en bout, comme le vivrait un vrai utilisateur. Comme ces tests sont lents et fragiles, on les réserve aux parcours les plus importants pour le business, par exemple l'inscription ou le paiement, sans chercher l'exhaustivité.

Pourquoi les tests de non-régression sont-ils importants ?

Les tests de non-régression garantissent qu'une nouvelle fonctionnalité, une correction ou une refactorisation ne casse pas ce qui marchait auparavant. C'est l'un des risques les plus insidieux du développement : corriger un bug ici et en introduire un autre ailleurs. Automatisée en intégration continue, la suite de non-régression sert de filet de sécurité qui permet de livrer fréquemment et en confiance. Ajouter un test de non-régression à chaque bug corrigé évite qu'il ne réapparaisse.

Quelle est la différence entre un test de fumée et un test sanity ?

Le test de fumée (smoke) est un ensemble réduit de vérifications sur les fonctions les plus critiques, exécuté juste après un nouveau build pour décider s'il est suffisamment stable pour être testé davantage. Sa portée est large mais superficielle. Le test sanity est une vérification étroite et ciblée, réalisée après une correction précise, pour confirmer que le problème est résolu avant d'engager une campagne complète. Le smoke valide le build, le sanity valide une correction.

Comment teste-t-on la sécurité d'une application ?

On teste la sécurité en combinant plusieurs approches : l'analyse statique du code (SAST) pour repérer les motifs dangereux, l'analyse dynamique (DAST) qui teste l'application en fonctionnement comme un attaquant, l'analyse des dépendances (SCA) qui confronte les bibliothèques aux vulnérabilités connues, et le test d'intrusion (pentest) mené par des experts. On s'appuie sur le référentiel OWASP Top 10 et on intègre ces vérifications tout au long du cycle, dans une logique DevSecOps, plutôt qu'à la fin.

Faut-il automatiser tous les tests ?

Non. L'automatisation est idéale pour la non-régression répétitive, stable et fréquente, comme les tests unitaires, d'intégration, d'API et certains end-to-end. En revanche, les tests exploratoires, l'évaluation de l'ergonomie et l'acceptation métier nécessitent l'intelligence humaine. La bonne approche combine automatisation pour la régularité et tests manuels pour la créativité et le jugement. Tout vouloir automatiser, y compris l'inautomatisable, est une erreur coûteuse.

Qu'est-ce qu'un test de mutation ?

Un test de mutation évalue la qualité de vos tests, et non celle de votre code. Un outil introduit de petites altérations dans le code source (les mutants), par exemple en inversant une condition, puis relance votre suite. Si un test échoue, le mutant est tué : vos tests sont efficaces. Si tous passent malgré l'altération, le mutant survit, révélant une zone mal protégée. Le score de mutation est un indicateur de qualité bien plus honnête que le simple pourcentage de couverture de code.

Combien de types de tests faut-il mettre en place sur un projet ?

Il n'y a pas de nombre idéal universel : tout dépend de la criticité, du stade et des ressources du projet. Un MVP se contente souvent de tests unitaires sur la logique clé, de quelques tests d'intégration et end-to-end, et de tests exploratoires. Un SaaS en croissance ajoute une non-régression automatisée complète et des tests de performance, sécurité, accessibilité et compatibilité. Le principe directeur est d'investir l'effort de test là où le risque et la criticité sont les plus élevés, plutôt que de tout tester aveuglément.

Un projet à fiabiliser ?

Captain Submit conçoit, teste et sécurise votre application de A à Z.

Réserver un appelNous écrire