Comment se matérialise un test unitaire ?

Avant d'écrire nos premiers tests unitaires, nous allons voir comment ces tests se matérialisent concrètement, indépendamment des langages de programmation. Ces concepts seront communs à tous les langages.

Un test, c'est une vérification

Le concept de test est simple : tester, c'est vérifier. Mais vérifier quoi ? Tout simplement une égalité, un fait, une appartenance, etc.

Les assertions

Les tests unitaires utilisent très largement la notion d'assertion. Comme sa définition l'indique, une assertion est une « proposition, de forme affirmative ou négative, qu'on avance et qu'on donne comme vraie » (Larousse).

Voici quelques types d'assertions que nous utiliserons pour écrire des tests unitaires, sans notion de langage de programmation (ces assertions sont implémentées dans la quasi totalité des frameworks de test).

Égalité

L'une des assertions les plus répandues est l'égalité. Il s'agit tout simplement de tester que deux éléments sont égaux, par exemple le résultat d'une fonction et une valeur.

On l'utilise de la sorte :

Cette instruction vérifie qu'une valeur x est bien égale à une autre valeur y : si c'est le cas, le test passe; si ce n'est pas le cas, le test échoue.

Modèle

egalite(x, y)

Exemples d'utilisation

egalite(2, 2) # succès
egalite(2, 5) # échec
egalite("Linus", "Linus") # succès
egalite("Steeve", "Bill") # échec
egalite("Bjarne", 1950) # échec

Selon les langages, cette assertion est appelée assertEquals, equals, isEqual

Vrai

Une autre assertion souvent utilisée consiste à vérifier la véracité d'une expression booléenne. Cette assertion ne prend qu'un argument :

Modèle

vrai(x)

Exemples d'utilisation

vrai(2 == 2) # succès
vrai(2 == 5) # échec
vrai(ma_variable) # succès si ma_variable vaut True, échec sinon

Selon les langages, cette assertion est appelée assertTrue, ok

Faux

Cette assertion est la simple opposée de la précédente : elle consiste à vérifier la non-véracité d'une expression booléenne. Cette assertion ne prend qu'un argument :

Modèle

faux(x)

Exemples d'utilisation

faux(2 == 2) # échec
faux(2 == 5) # succès
faux(ma_variable) # échec si ma_variable vaut True, succès sinon

Autres assertions

Il existe beaucoup d'autres assertions, parfois bien plus avancées que celles présentées sur cette page. Tout ceci dépend des langages et frameworks de test utilisés. En voici quelques-unes pour exemple, dans différents langages :

assertIn(x, y)

Permet de vérifier qu'un élément y fait partie d'une collection (liste, tuple, tableau…) x.

assertIsInstance(x, y)

Dans les langages orientés objet, permet de vérifier qu'un élément y est une instance de la classe x.

throws(instruction, exception)

Permet de vérifier que l'exécution de l'instruction instruction déclenche une exception exception.

Exécuter des tests

Nous avons vu plus haut le principe qui régit les tests unitaires : il s'agit d'écrire des vérifications sous la forme d'assertions.

Nous allons à présent présenter l'écosystème informatique (les outils, les procédés) qui permettent d'implémenter concrètement des tests. Pour le moment, nous allons garder un ppoint de vue général, sans entrer dans les détails d'implémentation de tel ou tel langage ou framework de test.

xUnit

xUnit désigne une architecture commune qu'implémentent les principaux frameworks de test unitaire, une généralisation de l'outil SUnit, framework de testing unitaire pour le langage Smalltalk, proposé par Kent Beck (par ailleurs créateur d'Extreme Programming et co-signataire du manifeste agile).

Les frameworks de test qui implémetent xUnit ont un certain nombre de caractéristiques en commun :

  • Ils implémentent les principales assertions que nous avons décrit plus haut.
  • Ils intègrent la notion de test case, notion fondamentale permettant de désigner un cas de test, une classe dont héritent l'ensemble des cas de test.
  • Ils intègrent la notion de fixture, permettant au programmeur de charger un ensemble de pré-requis (données de test notamment) définis ailleurs (fichiers indépendants) avant de lancer les tests à proprement parler.
  • Ils proposent un outil (généralement en ligne de commande) permettant de lancer les tests d'un système (tous ou un sous-ensemble) et de générer un rapport sur les erreurs éventuellement rencontrées. On appelle cet outil un test runner.

Exemple d'utilisation d'un test runner

$ python tests.py

...F.
======================================================================
FAIL: testFail (__main__.OutcomesTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "unittest_outcomes.py", line 39, in testFail
    self.failIf(True)
AssertionError: True is not false

----------------------------------------------------------------------
Ran 5 tests in 0.000s

FAILED (failures=1)
  • Un test runner xUnit possède une cinématique générique, et déroule les test de la manière suivante : exécution d'une méthode setup() permettant d'initialiser les tests et les jeu de test, exécution des tests à proprement parler, puis exécution d'une méthode tearDown() permettant de réaliser des actions post-tests, comme un nettoyage du jeu de test, suppression des données créées lors du test, etc.

Voici quelques exemples de frameworks de test implémentant xUnit :

Framework Langage
jUnit Java
unittest Python
qUnit Javascript
CppUnit C++
NUnit .NET
PHPUnit PHP

Pour une liste plus complète des frameworks de test (xUnit en particulier), voyez cet article : List of unit testing frameworks.

Testez vos connaissances !

Quelle est la différence entre ces assertions :

Vrai(1==1)

Egalite(1, 1)

  •  Il n'y en a pas.
  •  La première agit sur des chaînes de caractères, l'autre sur des nombres entiers.
  •  L'exécution de la seconde nécessite l'exécution préalable de la première.

Dans un test xUnit, à quoi sert la méthode setup() ?

  •  C'est l'endroit privilégié pour initialiser quelques données utiles à l'ensemble dans tests présents dans la classe de test.
  •  Il s'agit de la méthode permettant d'installer le framework de test dans le langage approprié.
  •  Il s'agit de la méthode permettant d'installer le framework de test sur l'OS courant.
  •  C'est une méthode exécutée systématiquement avant le lancement des tests de la classe de test.

Quel est le résultat du test suivant ?

x=[5,7,92]assertIn(2,x)
  •  Succès
  •  Échec
  •  Ne se prononce pas