Vous avez vu comment tester de façon unitaire du code assez simple. Bien évidemment, cela risque de se corser un peu dans le futur en fonction des situations auxquelles vous serez confronté.
Trouvez ce qu’il faut tester
Il n'est pas rare que l'on nous demande une couverture de code de 100 %.
Prenons un exemple avec le code suivant :
<?php
class Product
{
const FOOD_PRODUCT = 'food';
private $price;
private $type;
//...
public function computeTVA()
{
if ($this->price < 0) {
throw new \LogicException('The TVA cannot be negative.');
}
if (self::FOOD_PRODUCT == $this->type) {
return $this->price * 0.055;
}
return $this->price * 0.196;
}
}
Premier chemin à tester : le prix du produit doit être inférieur à 0.
if ($this->price < 0) {
throw new \LogicException('The TVA cannot be negative.');
Deuxième chemin à tester : le prix du produit doit être supérieur ou égal à 0, et le produit doit avoir un type ayant la valeur “food”.
if (self::FOOD_PRODUCT == $this->type) {
return $this->price * 0.055;
}
Troisième chemin à tester : le prix du produit doit être supérieur à 0, et le produit doit avoir un type différent de la valeur “food”.
return $this->price * 0.196;
Il existe plusieurs manières de tester une ligne de code donnée. Par ailleurs, un test doit aussi permettre de détecter les cas limites qui n'auraient pas été vus lors de l'élaboration des spécifications.
Il est important de concentrer vos efforts dans l'écriture de tests couvrant le code dit "critique" de votre application.
Je prends comme exemple une application e-commerce. Ce qui fait le succès de ce type de site, c'est l'affichage des produits et la possibilité de commander ceux-ci. Dans le cadre de tests unitaires, il faudrait donc prendre soin de faire en sorte que la description de produit comporte assez de caractères, ou qu'elle ait un titre bien formalisé, ou encore que la méthode en charge du calcul du total d'une commande fasse correctement son travail.
Retenez donc qu'il est important de tester ce qui est important pour le business de l'application. Ne visez pas le 100 % de couverture, visez le maximum de cas d'utilisation du code.
Détectez quand il faut tester
L'une des problématiques récurrentes dans l'écriture de tests est le temps à passer sur l'écriture de ceux-ci. Étant donné qu'il s'agit de code qui n'est pas directement exploitable par les utilisateurs de l'application, il est assez simple d'arriver à se dire, pris par les délais, que finalement, il n'est pas utile de les écrire.
Il vous arrivera également de passer par un sentiment de grande difficulté lorsque vous prendrez peut-être plus de temps à écrire un test qu'à écrire du code lié au fonctionnement même de votre application.
Écrire des tests demande une grande rigueur avec vous-même : en effet, il faut prendre le temps de lister ce qu'il faut tester, écrire ces tests, et surtout les maintenir à jour. Ce n'est pas une mince affaire !
Il est primordial d'intégrer ce temps d'écriture de tests dans vos estimations de temps (ou de complexité). Au même titre que l'écriture de code fonctionnel, les tests doivent faire partie du développement de l'application. Tout comme le temps que vous prenez à ouvrir votre navigateur pour lancer votre application web et la tester à la main, c'est du temps qu'il est absolument nécessaire de prendre !
Vous pouvez écrire vos tests à différents moments au cours de votre cycle projet :
avant d'écrire votre code fonctionnel ;
après avoir écrit votre code fonctionnel ;
lorsqu'un bug est détecté.
Avant d'écrire le code
On parle de Test Driven Development (TDD). Il s'agit de développement mené par les tests. Il y a 3 étapes à respecter :
Écrire le test.
Lancer le test et vérifier qu'il échoue.
Écrire le code fonctionnel.
Lancer le test et vérifier qu'il est OK.
Cette méthode est très rassurante étant donné qu'elle demande à ce que le test passe en premier, donc plus d'inquiétude quant à l'idée d'abandonner les tests !
Néanmoins, il faut à priori savoir ce que vous allez développer en matière de méthode(s) et classe(s)… Et soyons honnête, ce n'est pas toujours très clair avant de s'y mettre vraiment. C'est un pli à prendre, plus vous pratiquerez, plus ce sera simple.
Après avoir écrit le code
C'est ce qui est le plus communément fait. Il s'agit simplement de reprendre le code développé jusque-là, et de le tester afin de s'assurer qu’il fonctionne comme prévu.
Le danger ici est de se laisser aller à l'idée que finalement écrire un (ou plusieurs) test(s) n'est pas nécessaire, par manque de temps ou par excès de confiance.
Lorsqu'un bug est détecté
Plutôt que de se lancer tête baissée dans la correction du problème remonté, il faut :
Le reproduire avec un test.
S'assurer que le test échoue.
Écrire le code pour le corriger.
S'assurer que le test passe correctement.
Cette manière de faire permet d'accumuler une batterie de tests couvrant bon nombre de cas, au fur et à mesure des anomalies rencontrées. Cela permet également de s'assurer que, d'une anomalie à l'autre, la correction apportée n'introduit pas de régression.
Ces trois solutions peuvent être adoptées tout au long du projet ! Le plus important est d'être à l'aise, et surtout de ne pas abandonner l'écriture de tests !
Il est également intéressant de se mettre à l'écriture de tests pour une application dont on ne connaît pas le code : en effet, un test unitaire nécessite de connaître le code à tester. Cela force donc à lire ce code et à le comprendre.
En résumé
Il faut tester le code critique en premier lieu, c’est-à-dire ce qui concerne le cœur du projet.
On peut écrire nos tests avant d’avoir écrit le code (TDD), après, ou bien à la détection d’un bug, tout dépendra du temps que l’on vous accorde à les écrire.
Mais l’important reste de les écrire !
Rendez-vous au prochain chapitre pour découvrir le monde merveilleux de l'intégration continue.