Écrire des tests

Vision

Nous voulons rendre les tests manuels inutiles pour les développeurs du noyau, les auteurs de plugins, et les administrateurs de sites en rendant possible et en faisant la promotion de tests rapides et automatisés à tous les niveaux de Elgg.

Nous avons hâte d’un monde dans lequel les développeurs du noyau n’ont pas besoin de faire de tests manuels pour vérifier la correction du code contribué à Elgg. De manière similaire, nous envisageons un monde dans lequel les administrateurs de site peuvent mettre à niveau et installer de nouveaux plugins avec la certitude que tout fonctionne bien ensemble.

Effectuer les tests

Suite de tests du noyau Elgg

Actuellement nos tests se partagent en deux parties :
  • PHPUnit tests are located in /tests/phpunit – these are split between unit tests and integration tests.

Dans la mesure où il existe un fichier de configuration phpunit.xml à la racine d’Elgg, les tests devraient être aussi simples que :

git clone http://github.com/Elgg/Elgg
cd Elgg
phpunit

Tests des plugins

Idéalement, les plugins sont configurés d’une telle manière qu’ils peuvent faire l’objet de tests unitaires de la même manière que le noyau d’Elgg. Les développeurs de plugins sont libres d’implémenter leurs propres méthodes pour les tests unitaires, mais nous encourageons tout le monde à les rendre aussi simple que pour le noyau de Elgg :

git clone http://github.com/developer/elgg-plugin plugin
cd plugin
phpunit

Tests de bout en bout

Dans la mesure où les plugins de Elgg ont une telle capacité à remplacer, filtrer et modifier Elgg et le comportement d’autres plugins, il est important de pouvoir exécuter des tests de bout en bout sur un serveur de pré-production avec votre configuration finale avant de déployer vers la production.

Note

ToDo : Faciliter l’exécution de tous les tests d’intégration et d’acceptabilité depuis le panneau admin en utilisant la configuration courante du plugin. (sans s’inquiéter de corruption de la base de données !)

Motivation

Brièvement, les gains escomptés des tests sont :
  • Une confiance accrue dans le système.
  • Une plus grande liberté pour remanier le code.
  • Une documentation intégrée et à jour.

Nous adorons les contributions communautaires, mais afin de maintenir la stabilit » nous ne pouvons pas accepter de contributions extérieures sans vérifier au préalable leur correction. En promouvant les tests automatisés, les développeurs du noyau peuvent éviter les ennuis d’une vérification manuelle avant d’accepter un patch. Cela signifie également que les développeurs externes n’ont pas à perdre de temps à gagner la confiance de l’équipe du noyau. SI un patch arrive et qu’il dispose de tests pour le vérifier, nous pouvons être confiants dans le fait qu’il fonctionne sans avoir besoin de se soucier de la réputation de l’auteur.

Notez que ces bénéfices peuvent également s’étendre au dépôt des plugins. Les propriétaires de sites sont encouragés à « tester les plugins minutieusement » avant de les déployer sur un site de production. A la date de mars 2013, ceci signifie tester manuellement toutes les fonctionnalités que le plugin promet d’offrir. Mais Elgg fournit un grand nombre de fonctionnalités, et il n’est pas raisonnable de tester chacune d’entre elles sur chaque navigateur que vous voulez supporter et sur chaque appareil que vous voulez supporter ? Mais que se passerait-il si les développeurs de plugins pouvaient écrire des tests pour leurs plugins, et si les propriétaires de sites pouvaient simplement exécuter ces tests pour tous les plugins installés pour vérifier si la fonctionnalité est bien conservée ? Alors ils ne seraient pas limités à seulement prendre des plugins de développeurs « de confiance » ou des versions « stables ». Ils pourraient voir que, en réalité, rien n’a été cassé quand ils ont mis à niveau ce plugin critique depuis la version 1.3 vers la 2.5, et passer la mise à niveau en production en toute confiance.

La raison pour laquelle ce n’est pas le cas actuellement est parce qu’Elgg lui-même n’est pas encore si facile à tester à ce niveau. Nous voulons changer cela.

Stratégie

Nous avons quelques principes pour nous guider, dont nous pensons qu’ils seront utiles pour faire de cette vision une réalité.

En bref, nous prônons :
  • L’intégration continue – si Travis n’est pas content, nous non plus
  • L’injection des dépendances – Pour créer un code hautement testable et modulaire
  • BDD (« Behaviour Driven Development ») – Les tests devraient vérifier des fonctionnalités et fournir de la documentation, pas reprendre l’API de la Classe

Intégration continue

Nous exécutons tous nos tests sur Travis CI de sorte que nous puissions avoir un feedback en temps réel sur la correction des demandes de fusion entrantes et des développements au fur et à mesure de leur évolution. Si Travis n’est pas d’accord, nous ne faisons pas de commit sur le dépôt. Ceci nous permet de fusionner les demandes de fusion à un rythme rapide, dès lors qu’elles ont passé les tests. Cela nous permet également de rejeter les demandes de fusion sans investigation poussée si elles ne passent pas les tests. Nous pouvons aller au-delà de la question « est-ce que ça marche ou pas » et évoquer les choses dont les humains ont besoin de parler : la conception de l’API, l’utilité pour le projet, est-ce que cela fait partie du noyau ou pas, etc. Nous voulons qu’autant de fonctionnalités que possible fournies par le noyau d’Elgg puissent être vérifiées automatiquement par des tests exécutés sur Travis.

Injection des dépendances

Afin de maximiser la testabilité, toutes les dépendances doivent être explicites. Les fonctions globales, les Singletons, et les localisateurs de service sont mortels pour la testabilité parce qu’il est impossible de dire quelles dépendances se cachent sous le capot, et qu’il est encore plus difficile de simuler (« mock out ») ces dépendances. La capacité de simulation est critique parce que vous voulez que vos tests unitaires ne testent qu’une seule classe à la fois. Les échecs d’un test dans un TestCase ne devraient pas résulter d’une rupture dans une dépendance ; les échecs des tests ne devraient indiquer de rupture que dans la classe en train d’être testée. Ceci rend tout plus facile à déboguer. A la date de mars 2013, la majorité d’Elgg assume et utilise toujours un état global, et ceci a rendu Elgg et les plugins Elgg historiquement très difficiles à tester. Fort heureusement nous avons pris une autre direction depuis, et une grande partie du travail dans Elgg 1.9 a consisté à refactorer des composants du noyau pour qu’ils soient plus injectables sous forme de dépendances. Nous récoltons déjà les bénéfices de cet effort.

Développement orienté comportement

Pour nous ceci signifie que nous nommons les tests d’après les fonctionnalités plutôt que les méthodes. Quand vous testez des fonctionnalités, vous êtes encouragés à écrire moins de tests, plus petits, et plus logiques. Quand un test échoue, cela permet de savoir exactement quelle fonctionnalité est compromise. De plus, en nommant vos tests d’après les fonctionnalités, la liste des tests fournit une documentation des fonctionnalités que le système supporte. La documentation est typiquement quelque chose de problématique à conserver à jour, mais quand la documentation et la vérification sont une seule et même chose, il devient très facile de maintenir la documentation à jour.

Considérez ces deux méthodes de test :
  • testRegister()
  • testCanRegisterFilesAsActionHandlers()

En regardant seulement les noms, testRegister vous indique que la classe testée a probablement une méthode nommée « register ». Si ce test est passé, il vérifie probablement qu’elle se comporte correctement, mais ne vous dit pas ce qui caractérise un comportement correct, ou ce que l’auteur original du test essayait de vérifier. Si cette méthode a plusieurs usages corrects que vous devez tester, cette convention de nommage succincte vous encourage également à écrire un très long test qui teste toutes les conditions et fonctionnalités de ladite méthode. L’échec du test pourrait être causée par la compromission de n’importe laquelle d’entre elles, et cela prendra plus de temps pour savoir où se situe le véritable problème.

De l’autre côté, testCanRegisterFilesAsActionHandlers vous indique qu’il y a ces choses appelées « actions » qui ont besoin d’être « gérées » (« handled »), et que ces fichiers peuvent être enregistrés comme des gestionnaires valides pour les actions. Ceci expose mieux aux nouveaux venus la terminologie du projet et communique clairement l’intention du test pour ceux qui sont déjà familiers avec la terminologie.

Pour un bon exemple de ce que nous recherchons, regardez /tests/phpunit/Elgg/ViewServiceTest.php