Les tests automatisés, expliqués aux développeurs

Un code qui marche aujourd’hui n’est pas la question. La question, c’est ce qui se passe au prochain changement, et qui s’en aperçoit en premier.

Un test, c’est quoi ?

Un petit programme qui crée des données, fait jouer un scénario à Odoo et vérifie le résultat : « une commande confirmée crée bien sa livraison ». En Odoo, il s’écrit en Python dans le dossier tests/ du module, et une commande les lance tous en quelques secondes, sans personne devant l’écran. Un module en compte des dizaines.

Les règles

  • Écrits avec le code, d’après la demande

    Les tests partent de ce qui a été demandé, pas du code écrit. Ils couvrent le cas normal, les cas limites, les erreurs, et les droits d’accès : un utilisateur sans droit doit bien être refusé. Chaque test porte un nom qui se lit comme une phrase : test_a_cancelled_order_releases_its_stock, « une commande annulée libère son stock ».

  • Un bug : le test d’abord

    Quand un défaut est signalé, on écrit d’abord le test qui le reproduit, on le voit échouer sur le code actuel, puis on corrige. Un test qui n’a jamais échoué ne prouve rien. Avant de toucher un code ancien sans tests, on fige d’abord ce qu’il fait aujourd’hui dans des tests.

  • On ne tord jamais un test

    Un test rouge, c’est le code qu’on corrige, pas le test. Un test qui reste vert quand le code est faux (une vérification toujours vraie, un cas jamais exécuté) est un défaut, bloquant en revue, au même titre qu’un bug.

  • Pas de réseau

    Les services extérieurs (une banque, un transporteur) ne sont jamais appelés pendant les tests : on les remplace par une doublure, qui répond ce qu’on attend d’eux. Le résultat est le même sur chaque machine, à chaque passage.

  • Rejoués à chaque changement, comme la CI

    La CI (intégration continue) est un serveur qui rejoue tous les tests et les contrôles de qualité à chaque envoi de code. On lance les tests avec la commande que le dépôt documente, et on lit la ligne de bilan : « 0 failed, 0 error(s) of 18 tests ». Un bilan qui n’a joué aucun test ne vaut rien.

  • Une revue par quelqu’un d’autre

    Avant d’intégrer un changement, quelqu’un qui ne l’a pas écrit le relit : la demande est-elle couverte, un comportement est-il cassé, un test peut-il échouer, les droits d’accès sont-ils là. Chaque remarque cite le fichier et la ligne. La livraison dit ce qui a tourné, ou « rien n’a tourné ».

Un exemple : un bug signalé

Quatre étapes, toujours dans cet ordre.

  1. Le test d’abord

    Un test reproduit le défaut, tel qu’il a été décrit, avec les données du cas.

  2. Rouge sur l’ancien code

    La preuve que le test voit bien le défaut, et pas autre chose.

  3. La correction, la plus petite

    Le code change, le test passe, rien d’autre ne bouge.

  4. Vert à chaque envoi

    Le test reste et la CI le rejoue : le défaut ne revient pas sans être vu.

En pratique

Un test, nommé pour ce qu’il garantit : il crée ses données, joue le scénario, et vérifie une seule chose.

# timesheet_billing/tests/test_billing.py
from odoo.tests.common import TransactionCase


class TestBilling(TransactionCase):
    def test_a_billable_line_becomes_an_invoice_line(self):
        # Les données du cas : deux heures, facturables.
        line = self._timesheet(hours=2, billable=True)
        # Le scénario.
        invoice = line.bill()
        # Une seule vérification.
        self.assertEqual(invoice.amount_untaxed, 2 * line.rate)

La ligne de bilan, celle qu’on lit à la fin : combien de tests ont été joués, combien ont échoué. Ici, dix-huit tests, aucun échec.

0 failed, 0 error(s) of 18 tests when loading database 'test'

Ce que ça coûte

Écrire les tests prend du temps, et il est dans l’estimation. Une suite complète prend plusieurs minutes : on écrit le lot, on lance une fois, on corrige, on relance une fois. Et parfois, un refus de livrer « vite fait, sans test ».

Vous faites autrement ?

Un désaccord, une meilleure façon de faire, un cas qui ne rentre pas dans ces règles : écrivez-moi, je lis tout.

Me contacter

Les autres méthodologies