É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 :
  • Les tests PHPUnit sont situés dans /tests/phpunit – ceux-ci sont répartis entre les tests unitaires et les tests d’intégration.

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

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

Si vous écrivez un test unitaire, vous pouvez étendre la classe \Elgg\UnitTestCase ou si vous écrivez un test d’intégration, vous pouvez étendre la classe \Elgg\IntegrationTestCase. Ces classes ont des fonctions d’aide lors de l’écriture de tests. Les fonctions suivantes sont souvent utilisées :

  • up() - utilisé pour préparer chaque test exécuté dans le scénario de test

  • down() - exécuté après chaque test exécuté dans le scénario de test. Principalement utilisé pour nettoyer / restaurer.

  • createUser() - crée une entité ElggUser à utiliser dans votre test

  • createGroup() - crée une entité ElggGroup à utiliser dans votre test

  • createObject() - crée une entité ElggObject à utiliser dans votre test

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 de 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 en 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 se soucier 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.

  • Plus de 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. En mars 2013, ceci signifiait 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 publier la mise à niveau en production en toute confiance.

La raison pour laquelle ce n’est pas le cas actuellement est parce que 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 :
  • Intégration continue – si les vérifications de Github ne sont pas satisfaisantes, nous ne sommes pas satisfaits

  • L’injection des dépendances – Pour créer un code hautement testable et modulaire

  • BDD - « Behaviour Driven Development » ou Développement Orienté Comportement – Les tests devraient vérifier des fonctionnalités et fournir de la documentation, et pas simplement reprendre l’API de la Classe

Intégration continue

Nous exécutons tous nos tests avec les Actions GitHub afin de pouvoir obtenir des commentaires en temps réel sur l’exactitude des demandes de fusion -pull requests- et du développement au fur et à mesure de sa progression. ** Si les vérifications de GitHub ne réussissent pas, nous ne faisons pas de commit dans le dépôt. ** Cela nous permet de fusionner les demandes de fusion à un rythme rapide, tant qu’elles réussissent les tests. Cela nous permet également de rejeter les demandes de fusion sans examen détaillé si elles ne réussissent pas les tests. Nous pouvons dépasser la question « ça marche ou pas » et parler des choses dont les humains ont besoin de parler : la conception d’API, l’utilité pour le projet, si cela appartient au noyau ou à un plugin, etc. Nous voulons qu’autant de fonctionnalités que possible fournies par le noyau de Elgg -Elgg core- puissent être vérifiées automatiquement par des tests exécutés sur GitHub Actions.

Injection des dépendances

Afin de maximiser la testabilité, toutes les dépendances doivent être explicites. Les fonctions globales, les Singletons, et les localiseurs 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 modéliser ces dépendances. La capacité de modélisation est critique parce que vous voulez que vos tests unitaires ne testent qu’une seule classe à la fois. Les échecs de test dans un TestCase ne devraient pas aboutir à la rupture d’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. En mars 2013, l’essentiel de Elgg présupposait et utilisait encore l’état global, ce qui a rendu les plugins Elgg et le noyau Elgg historiquement très difficiles à tester. Heureusement, nous avons pris la direction opposée, et beaucoup de travail dans Elgg 1.9 a été consacré à la refactorisation des composants de base pour qu’ils soient plus dépendants et injectables. Nous récoltons déjà les fruits de cet effort.

Behavior-Driven Development - Développement Orienté Comportement

Pour nous ceci signifie que nous nommons les tests d’après les fonctionnalités plutôt que d’après 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 des 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