Vous êtes sur la page 1sur 27

Chapitre 2 : Les tests logiciels (tests unitaires)

I Introduction
Tout programme conséquent est composé de plusieurs unités, qui doivent idéalement être aussi
indépendantes que possible les unes des autres. Une unité est composée d’un petit nombre
(souvent 1) de classes indissociables. Par exemple, dans un programme de jeu de Monopoly,
on peut imaginer avoir une unité représentant la banque, une autre représentant le plateau de
jeu, etc

II Qu’est-ce qu’un test logiciel ?


Les tests d'application sont des tests de logiciels effectués à l'aide de scripts pour trouver des
erreurs dans une application et optimiser ses performances, son fonctionnement, sa stabilité et
d'autres aspects.

Cela permet d'améliorer la qualité de l'application tout en maximisant le retour sur


investissement (ROI) et en réduisant les efforts, le temps et les coûts de développement. Il
garantit que toutes les parties d'une application fonctionnent et fonctionnent de manière
optimale pour offrir une superbe expérience utilisateur.

III Utilité des tests applicatifs

Les applications logicielles sont devenues un élément essentiel du style de vie moderne dans la
vie personnelle et professionnelle. Vous avez besoin d'applications pour les achats en ligne, les
opérations bancaires, les divertissements, les études, le travail à domicile, les vidéoconférences
avec votre équipe, etc.

Ainsi, les utilisateurs recherchent des applications entièrement fonctionnelles qui peuvent leur
faciliter la vie et offrir des performances, une convivialité et des fonctionnalités de premier
ordre afin qu'ils puissent effectuer les actions souhaitées avec rapidité, précision et facilité.

Cette demande nécessite que vous développiez des applications capables de cocher toutes ces
cases pour ravir les utilisateurs finaux et stimuler votre entreprise. Et tester une application
nécessite que vous examiniez divers aspects d'un système tels que les caractéristiques, les
fonctionnalités, les performances, la facilité d'utilisation, l'interface, la fiabilité, etc.

Par conséquent, il existe des centaines de types de tests d'applications que vous pouvez choisir
en fonction de vos besoins. Et la connaissance des différents types de tests vous aidera à vérifier
votre application exactement pour les paramètres requis.

Par exemple, si vous souhaitez connaître les performances de votre application sur Android,
vous devez effectuer des tests de compatibilité. Mais si vous ne savez pas si quelque chose
comme ça existe, comment pourrez-vous le faire ?

J'espere que tu m'a bien compris.


Et lorsque vous effectuez le type idéal de test d'application, vous pouvez optimiser votre
application exactement pour ce paramètre. De même, vous pouvez effectuer des tests pour
toutes sortes de problèmes qui peuvent survenir. Ainsi, il vous aidera :

• Améliorer les fonctionnalités et fonctionnalités de l'application


• Éliminer les bugs facilement

• Améliorez les performances de l'application


• Assurer la sécurité des applications
• Rendez-le compatible avec diverses plates-formes, configurations matérielles et
environnements.
• Réduisez les dépenses inutiles
• Améliorer la convivialité
• Augmenter la fiabilité et la stabilité de l'application
• Optimisez la qualité globale de votre application

IV Les types de tests

Les tests d'application sont généralement classés en deux types :

• Test fonctionel
• Tests non fonctionnels

Comprenons chacun d'eux et leurs types en détail.

Tests fonctionnels
Les tests fonctionnels consistent à tester une application pour ses aspects fonctionnels. Il vérifie
chaque fonctionnalité de l'application pour s'assurer que tout fonctionne comme prévu. Vous
pouvez effectuer des tests fonctionnels à l'aide d'outils d'automatisation ou manuellement.

Les différents types de tests fonctionnels sont :

# 1. Tests unitaires

Tester chaque module ou composant d'une application pour vérifier s'il fonctionne comme
souhaité est appelé test unitaire. Cela nécessite une connaissance des langages de
programmation. Ainsi, ce sont les programmeurs qui effectuent ce test et non les testeurs. Ce
test est rigoureux car vous devez examiner attentivement chaque module et son code, et vous
devrez peut-être également développer des pilotes de test pour cela.

Tests unitaires sont effectués à la fois manuellement et à l'aide d'outils, mais ces derniers
fourniront une couverture et des performances de test maximales. Les outils que vous pouvez
utiliser pour les tests unitaires sont Nunit, JUnit, Unité PHP, TestNGet plus encore.

# 2. Test d'intégration
Une fois les modules intégrés, il est essentiel de vérifier s'ils fonctionnent correctement en tant
que modules combinés. C'est parce que l'intégration de plusieurs modules peut créer des bugs.
Ainsi, tester chaque module intégré d'une application pour vérifier sa fonctionnalité combinée
s'appelle un test d'intégration.

Les tests d'intégration vérifient les modules qui sont généralement des applications ou des
modules de code sur un réseau donné. Il est principalement réalisé pour les systèmes distribués
et les applications client ou serveur. Cela nécessite moins de tests que les tests unitaires et peut
adopter différentes approches, telles qu'une approche descendante, sandwich et ascendante.

Les outils de test d'intégration sont Sélénium, Rapporteur, Testeur fonctionnel IBM Rational,
etc.

# 3. Test du système

Les tests du système sont effectués pour vérifier l'ensemble du système pour sa fonctionnalité
selon les exigences du client. Il couvre toutes les parties du système dans son ensemble, visant
à produire une application avec les spécifications requises.

Le test système est une sorte de test de boîte noire et est également appelé test de scénario de
bout en bout que vous pouvez effectuer sur une application ou un système entièrement intégré.
Il vérifie soigneusement chaque entrée pour s'assurer que vous obtenez la sortie souhaitée.

Certains des outils de test du système sont Concombre, Karma, Jasmine, etc.

# 4. Test de santé mentale

Les tests d'intégrité déterminent si une nouvelle version de l'application fonctionne


correctement ou si elle n'est pas acceptée pour les tests majeurs. Il est effectué sur des
applications stables pour s'assurer qu'aucune modification ou correction de défaut ne puisse
interrompre les fonctionnalités de base de l'application après le test de régression.

Si votre application échoue lors de son utilisation initiale, cela signifie que l'application n'est
pas suffisamment stable pour effectuer d'autres tests. Dans ce cas, vous devrez corriger
l'application et la rendre stable pour d'autres tests.

Les tests d'intégrité sont effectués manuellement en analysant le comportement d'une


application après avoir apporté des modifications à une certaine partie de votre application.

# 5. Test de fumée

Lorsque l'équipe de développement fournit une nouvelle version d'application, l'équipe de test
vérifie la version pour s'assurer qu'il ne reste aucun problème majeur et que l'application est
stable pour effectuer des tests approfondis.

Si l'équipe de test détecte que la fonctionnalité de base de l'application est en quelque sorte
cassée dans la phase initiale, elle peut rejeter la nouvelle version, en informant l'équipe de
développement. Il est effectué avant une régression détaillée ou des tests fonctionnels sur la
version pour rejeter les applications défectueuses et faire gagner du temps à l'équipe d'assurance
qualité lors des tests et de l'installation de l'application.

Les tests de fumée sont effectués à la fois manuellement et à l'aide d'un outil d'automatisation
tel que Sélénium.

# 6. Test d'interface

La manière dont les différents composants d'une application, tels que la base de données, le
serveur, etc., communiquent entre eux peut affecter ses performances globales et, par
conséquent, l'interface doit être testée.

Ainsi, tester une application pour vérifier si les composants de l'application communiquent bien
et échangent correctement des données s'appelle un test d'interface. Il vérifie également la
gestion des erreurs pour s'assurer que chaque composant fonctionne correctement et se
comporte correctement avec les autres composants.

De plus, les tests d'interface valident si vous avez testé tous les logiciels et matériels pris en
charge et si les documents liés prennent en charge différentes plates-formes ou non. Il vérifie
également si la sécurité est maintenue pendant que les composants interagissent et avec quelle
efficacité l'application gère les pannes de réseau.

Certains outils de test d'interface sont Violoneux, Repos assuré, Facteur, etc.

# 7. Les tests de régression

Tester une application complète pour vérifier son fonctionnement après avoir modifié une
fonctionnalité, un composant ou un module est appelé test de régression. Il vise à garantir que
les fonctionnalités existantes de l'application restent inchangées après de nouvelles
modifications.

Il existe de nombreux outils de test de régression disponibles sur le marché, tels que Subject7,
TestSigma, Témoignage, TestCompleteet plus encore.

# 8. Test Alpha

Les tests alpha identifient tous les défauts, bogues et problèmes d'une application avant sa mise
sur le marché pour les consommateurs ou le client. Ces tests garantissent que les utilisateurs
obtiennent une application exempte de bogues et d'erreurs en évaluant sa qualité et sa
préparation pour les tests bêta.

Les tests alpha ont lieu sur le site du développeur ou en interne dans un environnement virtuel,
imitant un environnement utilisateur réel. Cela se fait vers la fin du développement de
l'application avant les tests bêta.

Vous pouvez utiliser des outils comme QA Mentor, SoapUI, etc., pour les tests alpha.
# 9. Test bêta

Les tests bêta sont effectués par le client ou un nombre limité d'utilisateurs dans l'environnement
réel pour vérifier la fonctionnalité, la convivialité et les performances globales d'une application
avant de la publier pour une utilisation réelle. Cela se fait après les tests alpha.

Les tests bêta vérifient si l'application présente des bogues ou des erreurs, fonctionne
correctement, fonctionne de manière optimale et est conviviale. L'équipe de développement
recueille les commentaires des utilisateurs pour améliorer les domaines où ils manquent. Par
conséquent, ils peuvent facilement apporter des modifications pour améliorer ses
fonctionnalités, ses performances, sa sécurité et sa convivialité.

Vous avez peut-être entendu parler des versions bêta de certaines applications ; cela signifie
que l'application est en cours de test bêta. Lorsque le test est terminé et que l'application est
améliorée, elle est mise en service. Les outils de test bêta sont Rail d'essai, UberTesteurs,
TestFée, Zephyr, etc.

Tests non fonctionnels


Les tests non fonctionnels consistent à vérifier les aspects non fonctionnels d'une application,
tels que l'utilisabilité, les performances, la sécurité, etc. Ils sont effectués après les tests
fonctionnels.

Les tests non fonctionnels visent à améliorer la qualité d'une application pour s'assurer qu'elle
fonctionne bien et offre une expérience utilisateur optimale. En général, elles ne sont pas
effectuées manuellement ; vous avez besoin d'outils d'automatisation pour cela.

Examinons certains types de tests non fonctionnels pour vos applications.

# 1. Test de performance

Les tests de performances vérifient si une application fonctionne conformément aux exigences.
Il vous indique si les performances de l'application présentent des problèmes qui la ralentissent
ou l'empêchent de fonctionner de manière optimale.

En comprenant les problèmes de performances liés à ce type de test, vous comprendrez


comment améliorer la vitesse, le temps de réponse, l'utilisation des ressources, le débit, etc. de
votre application.

Vous pouvez utiliser des outils de test de performance comme Testeur de performances
rationnelles, Apache JMeter, ChargeNinja, etc., pour tester les performances de votre
application.

# 2. test de charge

Les tests de charge sont un sous-ensemble des tests de performances qui vérifient la charge
qu'une application peut supporter avant que ses performances ne commencent à se dégrader.
Ce test est effectué en exécutant divers tests de charge pour connaître la capacité maximale de
l'application sous une charge donnée. Il vérifie également les problèmes susceptibles de
dégrader les performances de l'application.

En utilisant outils de test de charge tel que WebLOAD, LoadRunner, etc., sont utiles pour
déterminer la capacité de charge de votre application.

# 3. Test de stress

Si un système ou une application est sollicité au-delà de sa capacité, vous devez savoir quand
et comment il plante. Ce type de test est appelé test système. Il est exécuté sous des charges
massives telles que pousser l'application au-delà de sa capacité de stockage, de lourdes charges
de base de données, fournir des entrées en continu, etc.

Les tests de résistance visent à vérifier la stabilité et la fiabilité d'une application afin qu'elle
fasse preuve de résilience même pendant les pics d'utilisation. Il mesure la capacité de gestion
des erreurs de l'application et sa puissance sous de lourdes charges, garantissant qu'elle ne plante
pas dans de telles conditions.

Des outils tels que NéoLoad, Jmètre, LoadView, StressStimulus, etc., sont utiles pour les tests
de résistance.

# 4. Tests de volume

Le test de volume est un type de test de performance dans lequel une application est soumise à
de gros volumes de données pour vérifier son temps de réponse et son comportement. De gros
volumes de données dans la base de données d'une application sont donnés car cela a un impact
sur sa vitesse de traitement et ses temps de réponse. Il est également appelé test d'inondation.

Ainsi, vous pouvez vérifier l'efficacité de l'application en termes de volumes de données lourds
tout en détectant les problèmes qui réduisent les performances de l'application. Trouver les
problèmes vous aide à les résoudre rapidement et à optimiser leurs performances.

Les équipes de test de performance effectuent des tests de volume. Et les outils que vous pouvez
utiliser sont DbFit, NoSQLMap, MarteauDbet plus encore.

# 5. Test de sécurité

Tester une application pour vérifier sa sécurité contre les menaces externes et internes est appelé
test de sécurité. Ici, les menaces peuvent être des programmes malveillants, Les attaques DDoS,
virus et autres cybermenaces provenant d'agents internes d'une organisation ou d'attaquants
externes.

L'exécution de tests de sécurité indique également les capacités d'authentification et


d'autorisation d'une application et si elles sont suffisamment sécurisées ou non. Il vous aide à
trouver les vulnérabilités et les failles de sécurité à partir desquelles les menaces peuvent
pénétrer votre application. Ainsi, vous pouvez résoudre ces problèmes et combler les lacunes
pour assurer la sécurité de votre application.
De plus, les tests de sécurité vous aident à comprendre le comportement de l'application en cas
d'attaque ou de programmes malveillants et sa capacité à se remettre d'une attaque et de sa
maintenance après.

Les tests de sécurité sont généralement effectués par une équipe de test spéciale où toute forme
de piratage est injectée dans l'application pour vérifier sa sécurité. Des outils comme
ImmuniWeb, Wapiti, Acunetix, Google n'échoue pas, etc., peuvent être utilisés pour les tests
de sécurité.

# 6. Test de compatibilité

Les utilisateurs utilisent désormais diverses plates-formes telles que iOS, Android, Mac, PC,
Linux, etc., des navigateurs et des configurations. Par conséquent, il est essentiel de connaître
la compatibilité de votre application avec d'autres platesformes.

Le type de test qui évalue la façon dont une application s'exécute et se comporte sous différentes
plates-formes, serveurs Web, environnements réseau et configurations matérielles est appelé
test de compatibilité. Il garantit le bon fonctionnement d'une application avec des performances
optimales sur différents navigateurs, configurations, bases de données et versions de logiciels.

Vous pouvez utiliser des outils tels que Tourner la tête qui vous permet d'exécuter à distance
des tests multi-navigateurs sur des milliers d'appareils réels sur le cloud. Les utilisateurs
peuvent facilement tester la réactivité de leur application mobile ou de leur site Web et même
tester des performances vitales telles que des tests de charge sur des environnements réels pour
des résultats précis à 100 %.

Avantages

• Testez sur des milliers d'appareils réels pour une précision de 100 %
• Marquez et partagez les bogues avec des intégrations comme JIRA, mou, Trello
• Vérifiez et mesurez la qualité audio dans le monde entier pour les applications vocales
et le streaming audio. Prévisualisez les applications et surveillez l'expérience audio en temps
réel.

Certains autres outils sont CrossBrowserTest, LambdaTest et Expertise.

# 7. Test de fiabilité

Les tests de fiabilité font référence au processus de test d'une application pour vérifier si elle
peut fonctionner sans défaillance pendant une période spécifique dans un environnement donné.
Il vise à garantir que l'application est suffisamment fiable et exempte de bogues pour exécuter
son objectif de manière transparente.

Ce test vous dira si vous pouvez compter sur votre application pour effectuer la sortie souhaitée
à chaque fois que vous l'utilisez. Par exemple, tester la probabilité qu'un ordinateur puisse
fonctionner pendant sept heures sans tomber en panne.

Les tests de fiabilité détecteront les pannes répétées, la fréquence des pannes à un moment
donné et les causes des pannes afin que vous puissiez les réparer facilement et rapidement. Il
peut inclure des tests de charge d'application, des tests de régression et des tests de
fonctionnalités.

Vous pouvez utiliser des outils comme RCM, Weibull++, SOFTREL, etc., pour les tests de
régression.

# 8. Tests d'utilisabilité

Les tests d'utilisabilité signifient tester la convivialité d'une application. Il vérifie la facilité avec
laquelle un utilisateur peut comprendre et travailler avec votre application sans tracas ni
problèmes. Et s'ils rencontrent un problème ou rencontrent des difficultés lors de l'utilisation de
l'application, vous devrez le documenter.

En général, les tests d'utilisabilité vérifient la navigation de l'application pour s'assurer que
l'utilisateur atteint facilement la destination souhaitée dans l'application et exécute ses tâches
de manière transparente.

Pour les tests d'utilisabilité, un nombre limité d'utilisateurs ou le client est invité à utiliser
l'application. À ce stade, vous examinerez comment ils fonctionnent avec votre application et
s'ils ont besoin d'aide. Documenter les commentaires vous aidera à améliorer l'expérience
utilisateur.

Certains outils de test d'utilisabilité sont Crazyegg, Optimizely, TryMyUI, etc.

# 9. Test de réception

Le test d'acceptation est le dernier test d'application dans la phase de test. Il est effectué par
l'utilisateur final ou le client pour valider si l'application répond à tous les critères spécifiés, tels
que les préférences et les exigences.

Votre client acceptera l'application que vous avez développée si ses caractéristiques, ses
fonctions, sa convivialité et ses performances correspondent à ses besoins. Si oui, la demande
est approuvée pour la production. Mais si votre client n'aime pas quelque chose ou estime que
quelque chose devrait être amélioré, il peut vous demander de le modifier en conséquence.

V Les niveaux de tests

Introduction :
Il existe d’après ISTQB (International Software Testing Qualifications Board), 4 différents
niveaux de tests. Comme je l’ai déjà expliqué plusieurs fois dans mes articles précédents le test
ne se résume pas juste aux tests fonctionnels.

Ces niveaux de tests peuvent être représentés sous la forme de la pyramide cidessous :
A quoi ces niveaux de tests correspondent-ils ?

Les tests de composants :


Les tests de composants ont pour but de tester les différents composants du logiciel séparément
afin de s’assurer que chaque élément fonctionne comme spécifié. Ces tests sont aussi appelés
test unitaires et sont généralement écrits et exécutés par le développeur qui a écrit le code du
composant.
Pour une authentification, le bouton « se connecter » est un composant.
Ces tests sont (ou doivent théoriquement) toujours automatisés.

Les tests d’intégration :

Les tests d’intégrations sont des tests effectués entre les composants afin de s’assurer du
fonctionnement des interactions et de l’interface entre les différents composants. Ces tests sont
également gérés, en général, par des développeurs.
Toujours depuis l’authentification ici on vérifie que le message envoyé après l’appui sur le
bouton « se connecter » est bien reçu par le serveur d’authentification.
Ces tests peuvent être manuels ou automatisés.
Les tests système :

C’est les tests au sens le plus instinctif et c’est généralement les seuls qui sont effectués par les
ingénieurs de tests. Leurs but est de vérifier que le système (le logiciel ou l’application dans
son ensemble) répond aux exigences définies dans les spécifications. On les appelle souvent
tests fonctionnels même si c’est un abus de langage car il existe des tests « non fonctionnels»
qui peuvent être spécifiés (exemple de tests non fonctionnels : temps d’affichage d’une page).
Ici on vérifie que l’authentification fonctionne bien, que les bonnes erreurs sont remontées…

Ces tests peuvent être manuels ou automatisés, en général un mixte de tests automatisés et de
tests manuels est ce qui a le meilleur retour sur investissement.

Les tests d’acceptation :


Les tests « finaux » effectués par le métier ou les utilisateurs finaux (par exemple avec une bêta
test). Leurs but est de confirmer que le produit final correspond bien aux besoins des utilisateurs
finaux. Attention : ce n’est pas parce qu’une application répond aux spécifications qu’elle
répond aux besoins des utilisateurs. Cela peut arriver pour plusieurs raisons telles que des
problèmes (ou trous) dans les spécifications, des problèmes d’ergonomie…
Avec ces tests on vérifie qu’en plus de répondre aux exigences l’authentification correspond
bien à ce à quoi le métier ou les clients finaux s’attendent (un champ authentification trop petit
peut être problématique par exemple).
Les tests d’acceptation sont des tests manuels.

Conclusion :
ISTQB définit bien les différents niveaux de tests et permet d’avoir une vision plus claire du
test dans son ensemble.
Chaque niveau de test a sa place et doit être effectué avec rigueur. Ces niveaux de tests sont
généralement représentés par une pyramide car plus on est bas dans la pyramide plus le nombre
de cas de tests est censé être important.
Si l’on devait comparer ces niveaux de tests à la construction d’une maison voici à quoi
correspondrait chaque niveau de test :
– Les tests de composants aux vérifications matériaux de la maison
(briques, tuiles, isolant…).
– Les tests d’intégration à tout ce qui lie ces matériaux (le ciment pour les briques)
– Les tests systèmes à l’ensemble de la construction (la maison a-telle le bon nombre de
pièces, la bonne surface…)
– Les test d’acceptation à vérifier que la maison est bien vivable au jour le jour.

VI Tests en boîte noire ou blanche : quelles différences ?


Les tests en « boîte noire »
Les tests en « boite noire » consistent à examiner uniquement les fonctionnalités d’une
application, c’est-à-dire si elle fait ce qu’elle est censée faire, peu importe comment elle le fait.
Sa structure et son fonctionnement interne ne sont pas étudiés. Le testeur doit donc savoir quel
est le rôle du système et de ses fonctionnalités, mais ignore ses mécanismes internes. Il a un
profil uniquement « utilisateur ».

Ainsi, cette méthode sert à vérifier, après la finalisation d’un projet, si un logiciel ou une
application fonctionne bien et sert efficacement ses utilisateurs. En général, les testeurs sont à
la recherche de fonctions incorrectes ou manquantes, d’erreurs d’interface, de performance,
d’initialisation et de fin de programme, ou bien encore d’erreurs dans les structures de données
ou d’accès aux bases de données externes.

Pour cela, ils préparent des scénarios calqués sur les différents chemins utilisateur possibles sur
le système testé. Toutes les fonctionnalités doivent être prises en compte, pour qu’une fois tous
les tests effectués, elles aient toutes été éprouvées. Les tests consistent à suivre un scenario, et
à vérifier pour chaque fonctionnalité que les entrées (inputs) valides sont acceptées, que celles
non valides sont refusées, et bien entendu, qu’à chaque fois, le résultat (sortie ou output) attendu
est bien obtenu. C’est ce que l’on appelle la méthode « trial and error » (essais et erreurs).

Les avantages de cette méthode sont les suivants :

• Simplicité : ces tests sont simples à réaliser, car on se concentre sur les entrées et les
résultats. Le testeur n’a pas besoin d’apprendre à connaître le fonctionnement interne du
système ou son code source, qui n’est pas accessible. Cette méthode est donc également non
intrusive.
• Rapidité : en raison du peu de connaissances nécessaires sur le système, le temps de
préparation des tests est très court. Les scénarios sont relativement rapides à créer et à tester,
puisqu’ils suivent les chemins utilisateurs, qui sont relativement peu nombreux selon la taille
du système.
• Impartialité : on est ici dans une optique « utilisateur » et non « développeur ». Les
résultats du test sont impartiaux : le système marche, ou il ne marche pas. Il n’y a pas de
contestation possible, comme par exemple sur l’utilisation de tel processus plutôt qu’un autre
selon l’opinion du développeur.
Mais les tests en « boîte noire » ont également des inconvénients :

• Superficialité : étant donné que le code n’est pas étudié, ces tests ne permettent pas de
voir, en cas de problème, quelles parties précises du code sont en cause. De plus, les testeurs
peuvent passer à côté de problèmes ou vulnérabilités sous-jacentes. Certains problèmes sont
également difficilement repérables avec cette méthode, comme par exemple ceux liés à la
cryptographie, ou à des aléas de mauvaise qualité. C’est donc l’un des tests les moins exhaustifs.
• Redondance : si d’autres tests sont effectués, il est possible que celui-ci perde
grandement de son intérêt, puisque son champ d’action a tendance à être inclus dans celui
d’autres tests.
Dans le cas des tests d’intrusion

Dans le cas particulier des tests d’intrusion, le principe reste le même : les testeurs ne
connaissent rien sur le fonctionnement de l’application, et ils n’ont pas accès à son code source.
Ils se retrouvent donc dans la peau d’un internaute normal : c’est en général l’état dans lequel
se trouvent les pirates, ce qui rend ces tests très réalistes. Cependant, des connaissances en
programmation sont dans ce cas utiles, voire nécessaires, pour le testeur (comme pour un
pirate), car elles vont l’aider à identifier les tests pertinents à réaliser.

Cependant, les tests d’intrusion en boîte noire peuvent prendre beaucoup de temps (les testeurs
vont vérifier de nombreuses méthodes d’attaques différentes pour s’assurer qu’aucune ne
fonctionne). De plus, comme précisé plus haut, certaines parties de l’infrastructure du système
ne seront pas testées, car elles n’ont aucune influence sur l’interface utilisateur sur laquelle le
test a lieu.

Les tests en « boîte blanche »


Les tests en « boîte blanche » consistent à examiner le fonctionnement d’une application et sa
structure interne, ses processus, plutôt que ses fonctionnalités. Sont ici testés l’ensemble des
composants internes du logiciel ou de l’application, par l’intermédiaire du code source,
principale base de travail du testeur.

Pour réaliser un test en « boîte blanche », ce dernier doit donc avoir des compétences de
programmation, afin de comprendre le code qu’il étudie. Il doit également avoir une vue globale
du fonctionnement de l’application, des éléments qui la composent, et naturellement de son
code source. Contrairement aux tests en « boîte noire », le testeur ici a un profil développeur,
et non pas utilisateur.

En effectuant un test en « boîte blanche », on voit en effet quelle ligne de code est appelée pour
chaque fonctionnalité. Cela permet de tester le flux de données ainsi que la gestion des
exceptions et des erreurs. On s’intéresse également à la dépendance des ressources, ainsi qu’à
la logique interne et justesse du code. C’est pourquoi ces tests sont surtout utiles pendant le
développement d’une application, même s’ils peuvent être effectués durant de nombreuses
phases de la vie d’un projet. La méthode en « boîte blanche » peut être appliquée pour les tests
unitaires (majoritairement), les tests d’intégration et les tests système.

La méthode en « boîte blanche » utilise des scénarios de test, créés par le testeur selon ce qu’il
a appris du code source de l’environnement. L’objectif est qu’en testant l’ensemble de ces
scénarios, toutes les lignes de code soient vérifiées. Ce qui est regardé, c’est le processus
effectué par l’application après une entrée (input) pour obtenir un résultat. On ne fait que
vérifier si le code produit les résultats espérés.

Cette méthode a plusieurs avantages :

• Anticipation : effectuer ces tests au cours du développement d’un programme permet de


repérer des points bloquants qui pourraient se transformer en erreurs ou
• problèmes dans le futur (par exemple lors d’une montée en version, ou même lors de
l’intégration du composant testé dans le système principal).
• Optimisation : étant donné qu’il travaille sur le code, le testeur peut également profiter
de son accès pour optimiser le code, pour apporter de meilleures performances au système
étudié (sans parler de sécurité…).
• Exhaustivité : étant donné que le testeur travaille sur le code, il est possible de vérifier
intégralement ce dernier. C’est le type de test qui permet, s’il est bien fait, de tester l’ensemble
du système, sans rien laisser passer. Il permet de repérer des bugs et vulnérabilités cachées
intentionnellement (comme par exemple des portes dérobées). C’est notamment pour cela que
l’ARJEL impose des audits de code en « boîte blanche » aux opérateurs de jeux en ligne, afin
de s’assurer qu’aucun mécanisme caché ne vienne désavantager les joueurs.

Mais on ne peut pas tout avoir… C’est pourquoi ces tests ont également des inconvénients.

• Complexité : ces tests nécessitent des compétences en programmation, et une


connaissance accrue du système étudié.

• Durée : de par la longueur du code source étudié, ces tests peuvent être très longs.
• Industrialisation : pour réaliser des tests en « boîte blanche », il est nécessaire de se
munir d’outils tels que des analyseurs de code, des débogueurs… Cela peut avoir un impact
négatif sur les performances du système, voire même impacter les résultats.
• Cadrage : il peut être très compliqué de cadrer le projet. Le code source d’un programme
est souvent très long, il peut donc être difficile de déterminer ce qui est testé, ce qui peut être
mis de côté… En effet, il n’est pas toujours réaliste de tout tester, ce qui prendrait trop de temps.
Il est également possible que le testeur ne se rende pas compte qu’une fonctionnalité prévue
dans le programme n’y a pas été intégrée. Il n’est donc pas dans le scope du testeur de vérifier
si tout est là : il ne fait que tester ce qui est effectivement présent dans le code.
• Intrusion : cette méthode est très intrusive. Il peut en effet être risqué de laisser son code
à la vue d’une personne externe à son entreprise : il y a des risques de casse, de vol, voire même
d’intégration de portes dérobées… Choisissez donc toujours des testeurs professionnels !
Dans le cas des tests de pénétration

Si cette méthode est utilisée dans le cadre d’un test de pénétration, cela signifie que les testeurs
connaissent le fonctionnement du système attaqué : ils ont accès au code source, au design de
l’architecture de l’application… Les testeurs se basent alors sur ces connaissances pour élaborer
des tests permettant de vérifier la sécurité de l’application.

Cela permet notamment, par rapport à la méthode en « boîte noire », de tester la qualité de code,
et d’avoir un champ d’action beaucoup plus étendu. Cependant, cette méthode ne permet pas
de tester l’application en conditions « réelles », car aucun pirate n’aurait accès à autant
d’information ; elle permet pourtant de sécuriser efficacement son application, notamment
contre les menaces internes !

Les tests en « boîte grise »


Les tests en « boîte grise » compilent ces deux précédentes approches : ils éprouvent à la fois
les fonctionnalités et le fonctionnement d’un système. C’est-à-dire qu’un testeur va par exemple
donner une entrée (input) à un système, vérifier que la sortie obtenue est celle attendue, et
vérifier par quel processus ce résultat a été obtenu.

Dans ce type de tests, le testeur connaît le rôle du système et de ses fonctionnalités, et a


également une connaissance, bien que relativement limitée, de ses mécanismes internes (en
particulier la structure des données internes et les algorithmes utilisés). Attention cependant, il
n’a pas accès au code source !

Ces tests peuvent difficilement être effectués pendant la phase de développement du projet, car
elle implique des tests sur les fonctionnalités du programme : celui-ci doit déjà être dans un état
proche de final pour que ces tests puissent être pertinents. En effet, pendant les tests en « boîte
grise », ce sont surtout des techniques de « boîte noire » qui sont utilisées, puisque le code n’est
pas accessible. Cependant, les scénarios sont orientés pour jouer sur les processus sous-jacents,
et ainsi les tester également.

Bien entendu, la méthode « boîte grise » combine surtout les avantages des méthodes « boîte
blanche » et « boîte noire ». On peut cependant noter deux gros bénéfices de cette technique :

• Impartialité : les tests en « boîte grise » gardent une démarcation entre les développeurs
et le testeur, puisque ce dernier n’étudie par le code source et peut s’appuyer sur les résultats
obtenus en testant l’interface utilisateur.
• Intelligence : en connaissant la structure interne du programme, un testeur peut créer
des scénarios plus variés et intelligents, afin d’être certain de tester toutes les fonctionnalités
mais également tous les processus correspondants du programme.

En parallèle, l’un des inconvénients les plus importants de ces tests est le suivant :

• Non exhaustivité : étant donné que le code source n’est pas accessible, il est impossible
avec des tests en « boîte grise » d’espérer avoir une couverture complète du programme.
Dans le cas des tests de pénétration

Dans le cas des tests de pénétration, la méthode « boîte grise » consiste à effectuer les tests en
étant logué sur l’application avec un compte utilisateur. C’est un niveau intermédiaire, où les
testeurs connaissent les mécanismes internes de l’application, et qui les oriente dans leurs choix
de tests. Il permet de créer des tests relativement exhaustifs, tout en les maintenant dans une
optique relativement réaliste et proche de ce que pourrait faire un réel pirate.

Pour mieux comprendre…


Une analogie est souvent utilisée pour différencier ces techniques, en comparant le système
testé à une voiture.
• En méthode « boîte noire », on vérifie que la voiture fonctionne en allumant les lumières,
en klaxonnant et en tournant la clé pour que le moteur s’allume. Si tout se passe comme prévu,
la voiture fonctionne.
• En méthode « boîte blanche », on emmène la voiture chez le garagiste, qui regarde le
moteur ainsi que toutes les autres parties (mécaniques comme électriques) de la voiture. Si elle
est en bon état, elle fonctionne.
• En méthode « boîte grise », on emmène la voiture chez le garagiste, et en tournant la clé
dans la serrure, on vérifie que le moteur s’allume, et le garagiste observe en même temps le
moteur pour s’assurer qu’il démarre bien selon le bon processus.

VII Les tests unitaires


Le test unitaire ou test par unité (unit testing) consiste à écrire des petits programmes s’assurant
que chaque unité se comporte comme elle le devrait. Ces tests doivent être automatiques, dans
le sens où il ne doit pas être nécessaire qu’un humain examine le résultat de leur exécution pour
savoir qu’un problème est survenu. Il est alors possible de les lancer très fréquemment — p.ex.
après chaque modification — et de détecter les problèmes dès leur apparition.

Les tests unitaires automatisés avec PHPUnit


Un test automatisé est un programme qui se découpe en trois phases dites AAA
pour Arrange, Act, Assert.
Arrange

La mise en place de l’environnement : création et initialisation des objets


nécessaires à l’exécution du test.
Act

Le test proprement dit.


Assert

La vérification des résultats obtenus par le test.


Le sous-système (l’ensemble des objets) éprouvé par le test est parfois
appelé SUT (System Under Test).

PHPUnit
PHPUnit est un framework de tests unitaires pour PHP. Il s’inspire de JUnit, la
version Java du framework.
PHPUnit fournit son propre exécutable phpunit pour exécuter les tests. Il fournit
également une bibliothèque de classes nécessaire pour la rédaction des tests.

Structure d’une classe de test PHPUnit


Comme PHP est un langage orienté Objet, les tests PHPUnit sont regroupés dans des
classes de test. Généralement, on groupe dans une classe les tests ayant la même
classe comme point d’entrée et on nomme la classe de test à partir du nom de la
classe testée suffixé par , Test . Par exemple, pour tester la classe ConversionDate on
créera une classe .
ConversionDateTest
Suffixer par Test le nom de la classe de test est juste une convention. Néanmoins, il est très
fortement conseillé de la respecter car les outils utilisent également cette
convention pour découvrir les classes de test à exécuter.
Les méthodes de test
Une classe de test est une classe qui hérite de la classe . Elle TestCase déclare des méthodes
publiques sans paramètre et dont le nom commence par . Ces méthodes
ne doivent pas retourner de valeur particulière. test

Note

Vous pouvez alternativement utiliser l’annotation @test au dessus de la déclaration


d’une méthode de test. Ainsi, le format du nom de la méthode est libre.
Une méthode de test contient :
• un ensemble d’instructions correspondant à la phase arrange (si
nécessaire),
• un ensemble d’instructions correspondant à la phase act (qui se limite
généralement à l’appel de la méthode à tester),

• un ensemble d’instructions correspondant à la phase assert.


L’exemple ci-dessous teste la fonction strtoupper qui renvoie une chaîne de

<?php

use PHPUnit\Framework\TestCase;

class StringTest extends TestCase


{
public function test_strtoupper_produit_une_chaine_en_majuscule()
{
// Bloc arrange
$s = "Bonjour le monde";
// Bloc act
$maj = strtoupper($s);

// Bloc assert
$this->assertEquals("BONJOUR LE MONDE", $maj);
}

}
Une méthode de test ne doit pas contenir d’instruction if ou switch puisqu’un test
traduit un cas d’utilisation simple sans choix possible.
.
De même, une méthode de test ne devrait contenir for while
ou
qu’exceptionnellement des boucles
Les assertions
La classe TestCase fournit des méthodes pour
n qui
déclarer des assertions. Ces méthodes
permettent de vérifier la valeur d’un paramètre ou de
comparer deux valeurs passées en paramètres. Si
l’assertion est fausse, ces méthodes produisent une
exceptio fait échouer le test.

Parmi les méthodes d’assertion, on trouve :


Méthode Utilisation

assertTrue($condition) Vérifie que la condition passée en paramètre est vraie.

assertFalse($condition) Vérifie que la condition passée en paramètre est fausse.

Compare les deux paramètres pour vérifier qu’ils sont


assertEquals($expected, $actual) égaux.

Compare les deux paramètres pour vérifier qu’ils ne


assertNotEquals($expected, $actual)
sont pas égaux.

Vérifie que les deux objets passés en paramètre sont en


assertSame($expected, $actual) fait le même objet en mémoire.

Vérifie que les deux objets passés en paramètre ne sont


assertNotSame($expected, $actual)
pas les mêmes objets en mémoire.

Vérifie que l’expression passée en paramètre s’évalue


assertNull($actual)
à null .

Vérifie que l’expression passée en paramètre ne


assertNotNull($actual) null s’évalue pas à .
Chacune des méthodes précédentes accepte une chaîne de caractères comme
dernier paramètre optionnel. Il s’agit du message d’erreur produit dans le rapport de
test si l’assertion échoue.
Note

Pour les méthodes d’assertion qui attendent deux valeurs pour les comparer, notez
que la première valeur correspond à la valeur attendue pour ce test et la deuxième
valeur correspond à la valeur produite au moment du test. Exemple d’utilisation des
assertions
<?php
use PHPUnit\Framework\TestCase;

class StringTest extends TestCase


{
public function test_exemple_assertions()
{
$s = "Bonjour le monde";

$this->assertEquals("Bonjour le monde", $s);


$this->assertNotEquals("Bonsoir le monde", $s);
$this->assertFalse(empty($s));
}

}
Pour une présentation exhaustive des méthodes d’assertion, consultez la documentation
officielle.
Exercice - Tests unitaires de abs

Écrire les tests unitaires pour la fonction abs.


Note

L’exercice précédent propose de tester une fonction sans effet de bord (ce que l’on
appelle également une fonction pure). Les tests sur ce type de fonction sont faciles à
écrire. Ils restent cependant l’exception lorsqu’on utilise la programmation orientée
objet. En effet, l’appel d’une méthode sur un objet modifie le plus souvent son état et provoque
généralement des effets de bord en sollicitant d’autres objets avec lesquels
l’objet entretient des dépendances.
Les fixtures
Pour réaliser un test, il est parfois nécessaire de disposer d’un grand nombre d’objets
correctement initialisés et de préparer le SUT (System Under Test). Plutôt que d’écrire le
code nécessaire au début d’un test (au risque de le rendre moins lisible), on préfère écrire ce code
dans une classe à part ou une méthode à part. Dans ce cas, on qualifie ce nouvel objet ou
cette nouvelle méthode de fixtures.

Avec PHPUnit, il est possible d’exécuter des méthodes avant et après chaque test pour allouer
et désallouer des ressources nécessaires à l’exécution des tests. On
déclare pour cela des méthodes publiques sans paramètre annotées avec @before ou
@after.
Exemple d’une classe de test avec @before et @after
<?php
use PHPUnit\Framework\TestCase;

class UneClasseTest extends TestCase


{

/**
* @before */
public function initTestEnvironment()
{
// cette méthode est exécutée avant chaque test
}

/**
* @after */
public function destroyTestEnvironment()
{
// cette méthode est exécutée après chaque test
}
public function testMethode()
{
// la méthode de test
}
}
Note

Il est également possible de déclarer des méthodes static annotées


avec @beforeClass ou @afterClass. Ces méthodes ne sont appelées qu’une seule fois
respectivement avant ou après l’ensemble des méthodes de test de la classe.

VIII JUnit
Les tests unitaires automatisés avec JUnit
Un test automatisé est un programme qui se découpe en trois phases dites AAA
pour Arrange, Act, Assert.
Arrange

La mise en place de l’environnement : création et initialisation des objets


nécessaires à l’exécution du test.
Act

Le test proprement dit.


Assert

La vérification des résultats obtenus par le test.

Le sous-système (l’ensemble des objets) éprouvé par le test est parfois


appelé SUT (System Under Test).

On distingue différentes catégories de tests :


• Tests unitaires : testent une partie (une unité) d’un système afin de
s’assurer qu’il fonctionne correctement (build the system right)
• Tests d’acceptation : testent le système afin de s’assurer qu’il est conforme aux
besoins (build the right system)
• Tests d’intégration : testent le système sur une plate-forme proche de la plate-
forme cible
• Tests de sécurité : testent que l’application ne contient pas de failles de sécurité
connues (injection de code, attaque XSS, …)
• Tests de robustesse : testent le comportement de l’application au limite des
ressources disponibles (mémoire, CPU, …) sur la plate-forme

JUnit
JUnit est le framework de tests unitaires le plus utilisé en Java.

Structure d’une classe de test JUnit


Comme Java est un langage orienté Objet, les tests JUnit sont regroupés dans des classes
de test. Généralement, on groupe dans une classe les tests ayant la même classe comme
point d’entrée et on nomme la classe de test à partir du nom de la classe testée préfixé ou
suffixé par en la plaçant dans le même package. Par
Test
exemple, pour tester la classe , on DateFormatter créera une classe .
TestDateFormatter DateFormatterTest
ou Test Suffixer ou post-fixer par le nom de la
classe de test est juste une convention.
Néanmoins, il est très fortement conseillé de la respecter car les IDE et Maven utilisent
également cette convention pour découvrir les classes de test à exécuter.
Exécution des tests JUnit
JUnit est pris en charge par les IDE Java et par les outils de build comme Maven.

Dans Eclipse, il suffit de faire un clic droit dans l’explorateur de projet sur un fichier source,
une classe de Test ou un package et de choisir « Run as… > JUnit Test ». On peut
également presser la touche F11 dans l’éditeur de code source de la classe de test.

Les méthodes de test


Une classe de test est simplement une classe déclarant des méthodes publiques sans
paramètre et sans valeur de retour et qui sont annotées par @Test.

Une méthode de test contient :


• un ensemble d’instructions correspondant à la phase arrange (si
nécessaire),
• un ensemble d’instructions correspondant à la phase act (qui se limite généralement à l’appel
de la méthode à tester),

• un ensemble d’instructions correspondant à la phase assert.

package dev.gayerie;

import static org.junit.Assert.*; import org.junit.Test;

public class StringTest {


@Test
public void upperCaseProduitUneChaineEnMajuscules() throws Exception {
// Bloc arrange
String s = "Bonjour le monde";
// Bloc act
String maj = s.toUpperCase();

// Bloc assert
assertEquals("BONJOUR LE MONDE", maj);
}

}
Une méthode de test ne devrait pas contenir if ou switch puisqu’un
d’instruction test traduit un cas d’utilisation simple sans for while même, une
choix possible. De test ne devrait contenir ou méthode de
qu’exceptionnellement des boucles .
il contenant
Les assertions des méthodes
La classe Assert est une classe out des assertions. Ces statiques pour
déclarer
méthodes permettent de vérifier la valeur d’un
paramètre ou de
comparer deux valeurs passées en paramètres. Si
qui fait
l’assertion est fausse, ces méthodes
AssertionError échouer le test.
produisent une exception de type

Parmi les méthodes d’assertion, on trouve :


Méthode Utilisation
assertTrue(boolean condition) Vérifie que la condition passée en paramètre est vraie.

Méthode Utilisation

assertFalse(boolean condition) Vérifie que la condition passée en paramètre est fausse.

assertEquals(Object expected,
Object actual) Compare les deux paramètres pour vérifier qu’ils sont égaux.

assertNotEquals(Object expected, Compare les deux paramètres pour vérifier qu’ils ne sont pas
Object actual) égaux.
assertSame(Object expected, Vérifie que les deux objets passés en paramètre sont en fait le
Object actual)
même objet (en utilisant l’opérateur == ).

assertNotSame(Object expected, Vérifie que les deux objets passés en paramètre ne sont
Object actual) pas les mêmes objets (en utilisant != l’opérateur ).
Vérifie que l’expression passée en paramètre s’évalue
assertNull(Object actual)
à null .
Vérifie que l’expression passée en paramètre ne
assertNotNull(Object actual) null s’évalue pas à .

Il ne s’agit pas vraiment d’une assertion puisqu’un appel à cette


méthode fait échouer le test immédiatement. Nous verrons plus
fail() bas que cette méthode est utile pour tester les exceptions.

Il existe une surcharge de méthode pour chacune des méthodes précédentes qui
accepte une chaîne de caractères comme premier paramètre. Il s’agit du message
d’erreur produit par le test si l’assertion échoue.
Note

Pour les méthodes d’assertion qui attendent deux valeurs pour les comparer, notez
que la première valeur correspond à la valeur attendue pour ce test et la deuxième
valeur correspond à la valeur produite au moment du test. Exemple d’utilisation des
assertions
package dev.gayerie;

import static org.junit.Assert.*; import org.junit.Test;

public class StringTest {


@Test
public void testString() throws Exception {
String s = "Bonjour le monde";

assertEquals("Bonjour le monde", s); assertNotEquals("Bonsoir le monde", s);


assertFalse(s.isBlank());
}

}
Exercice - Tests unitaires de java.util.Math#abs(int)

exotest.zip
Note

L’exercice précédent propose de tester une méthode sans effet de bord (ce que l’on appelle
également une fonction pure). Les tests sur ce type de méthodes sont faciles à écrire. Ils
restent cependant l’exception lorsqu’on utilise la programmation orientée objet. En effet,
l’appel d’une méthode sur un objet modifie le plus souvent son état et provoque généralement
des effets de bord en sollicitant d’autres objets avec lesquels l’objet entretient des dépendances.
Les fixtures
Pour réaliser un test, il est parfois nécessaire un grand nombre d’objets et de préparer le
SUT (System Under Test). Plutôt que d’écrire le code nécessaire au début d’un test (au risque
de le rendre moins lisible), on préfère écrire ce code dans une classe à part ou une méthode à
part. Dans ce cas, on qualifie ce nouvel objet ou cette nouvelle méthode de fixtures.

Avec JUnit, il est possible d’exécuter des méthodes avant et après chaque test pour allouer et
désallouer des ressources nécessaires à l’exécution des tests. On déclare
pour cela des méthodes publiques sans paramètre annotées avec @Before ou @After.
Exemple d’une classe de test avec @Before et @After
import org.junit.After; import org.junit.Before; import org.junit.Test;
import static org.junit.Assert.*;

public class UneClasseTest {


@Before
public void initTestEnvironment() {
// cette méthode est exécutée avant chaque test
}
@After
public void destroyTestEnvironment() {
// cette méthode est exécutée après chaque test
}
@Test
public void methodeDeTest() throws Exception {
// la méthode de test
}
}
Note

Il est également possible de déclarer des méthodes static annotées


avec @BeforeClass ou @AfterClass. Ces méthodes ne sont appelées qu’une seule fois
respectivement avant ou après l’ensemble des méthodes de test de la classe.
Tester les exceptions
Grâce aux tests unitaires, il est également plus facile de tester les cas non nominaux qui se
traduisent la plupart du temps par la production d’une exception en Java. Si on désire tester un
cas d’erreur par exemple, cela signifie que le test sera ok si une exception précise est produite
lors de la phase act.

Avec JUnit, il existe plusieurs façons d’écrire un test pour une telle situation. Pour les
exemples suivants, nous testerons la méthode Integer#parseInt qui produit une exception
de type NumberFormatException lorsqu’une chaîne de caractères qui ne correspond pas à un
nombre est passée en paramètre d’appel.
Tester une exception (façon 1)
package dev.gayerie;
import static org.junit.Assert.fail; import org.junit.Test;

public class IntegerTest {


@Test
public void parseIntThrowsExceptionWhenNotANumber() throws Exception { try {
Integer.parseInt("not a number"); fail("NumberFormatException expected");
} catch (NumberFormatException e) {
}
}

}
Dans l’exemple ci-dessus, on utilise une structure try ... catch pour attraper
l’exception qui est attendue. Dans le bloc faire , l’appel à la
try Assert.fail pour
échouer le test si jamais la phase act (c’est- àpas méthode dire
produit d’exception. Cette façon d’écrire le test est l’appel à Integer#parseInt) n’a
simple mais rend le test parfois difficile à lire à cause catch et de l’absence
de la présence des blocs d’une phase assert try ...
remplacée par l’appel à Assert.fail .

Tester une exception (façon 2)


package dev.gayerie;

import org.junit.Test;

public class IntegerTest {

@Test(expected = NumberFormatException.class)
public void parseIntThrowsExceptionWhenNotANumber() throws Exception {
Integer.parseInt("not a number");
}

}
Dans l’exemple ci-dessus, on utilise l’attribut expected de l’annotation @Test qui
permet d’indiquer que l’on s’attend à ce que le test
échoue à cause de la propagation d’une exception considéré en échec). Cette façon
(si ce n’est pas le cas, le test sera d’écrire le test est
plus simple que précédemment mais elle peut être n’est pas
explicite
difficile à comprendre car la phase assert dans la
Tester une exception (façon 3) méthode.
package dev.gayerie;

import org.junit.Rule; import org.junit.Test;


import org.junit.rules.ExpectedException;

public class IntegerTest {


@Rule
public ExpectedException expectedException = ExpectedException.none(); @Test
public void parseIntThrowsExceptionWhenNotANumber() throws Exception {
expectedException.expect(NumberFormatException.class);

Integer.parseInt("not a number");
}

}
Dans l’exemple ci-dessus, on utilise une rule JUnit pour signaler avant la phase act que
l’on attend une exception. Comme précédemment, cette façon d’écrire peut être difficile à
comprendre car la phase assert est remplacée par un attendu lors de la phase arrange.
Note

Cette approche est dépréciée à partir de JUnit 4.13.


Tester une exception (façon 4)
package dev.gayerie;

import static org.junit.Assert.assertThrows;

import org.junit.Test;

public class IntegerTest {


@Test
public void parseIntThrowsExceptionWhenNotANumber() throws Exception {
assertThrows(NumberFormatException.class, () -> {
Integer.parseInt("not a number");
});
}

}
Avec l’introduction des lambdas depuis Java 8, il est plus direct d’encapsuler un appel
d’un code produisant une exception dans une fonction anonyme. On utilise pour cela en
précisant le type de l’exception attendue. Si cette
Assert.assertThrows
approche est élégante, elle mélange tout de même les codes de la
phase act et de la phase assert.

Utilisation de doublure
Parfois, il est utile de contrôler l’environnement de test d’un objet ou d’une
collaboration d’objets. Pour cela, on peut faire appel à des doublures qui vont se
substituer lors des tests aux objets réellement utilisés lors de l’exécution de
l’application dans un environnement de production.
Simulateur

Un simulateur fournit une implémentation alternative d’un sous-système. Un


simulateur remplace un sous-système qui n’est pas disponible pour
l’environnement de test. Par exemple, on peut remplacer un système de base
de données par une implémentation simplifiée en mémoire.
Fake object

Un fake object permet de remplacer un sous-système dont il est difficile de


garantir le comportement. Le comportement du fake object est défini par le
test et est donc déterministe. Par exemple, si un objet dépend des
informations retournées par un service Web, il est souhaitable de remplacer
pour les tests l’implémentation du client par une implémentation qui
retournera une réponse déterminée par le test lui-même.
Mock object

Un objet mock est proche d’un fake object sauf qu’un objet mock est également capable de
faire des assertions sur les méthodes qui sont appelées et les paramètres qui sont transmis
à ces méthodes.
Implémentation d’objet mock avec Mockito
Mockito est un framework Java pour faciliter la création d’objets mocks à partir d’une classe
ou d’une interface.
La méthode statique Mockito.mock(Class<?>) permet de créer une instance d’un mock à partir
d’une classe ou d’une interface. L’instance d’objet retournée par cette
méthode est instrumentalisée par Mockito. Il est possible d’enregistrer sur ce mock des
comportements lors de la phase arrange grâce, notamment, à la

méthode Mockito.when(Object) . Lors de la phase assert, il est possible de vérifier que


les appels de méthodes programmés sur le mock ont bien été réalisés grâce à la méthode
Mockito.verify(Object) .

Exemple d’une classe de test utilisant Mockito


import static org.junit.Assert.*;
import javax.servlet.http.HttpServletRequest;

import org.junit.Test; import org.mockito.Mockito;

public class TestWithMockito {


@Test
public void testDemoMockito() throws Exception {
HttpServletRequest mockedRequest = Mockito.mock(HttpServletRequest.class);
Mockito.when(mockedRequest.getParameter("login")).thenReturn("monlogin");
String parameterValue = mockedRequest.getParameter("login");

assertEquals("monlogin", parameterValue);
Mockito.verify(mockedRequest).getParameter("login");
}
}
import static org.junit.Assert.*; import static org.mockito.Mockito.*;

import javax.servlet.http.HttpServletRequest;

import org.junit.Test;

public class TestWithMockito {


@Test
public void testDemoMockito() throws Exception {
HttpServletRequest mockedRequest = mock(HttpServletRequest.class);
when(mockedRequest.getParameter("login")).thenReturn("monlogin");

String parameterValue = mockedRequest.getParameter("login");

assertEquals("monlogin", parameterValue);
verify(mockedRequest).getParameter("login");
}

}
Les exemples de code ci-dessus ne sont bien évidemment pas de vrais tests JUnit puisqu’ils
se contentent de tester le bon fonctionnement de Mockito.

La documentation de Mockito est accessible ici.

Vous aimerez peut-être aussi