Tests d'intégration, quézako ?
Les tests unitaires c'est bien, mais ce n'est pas suffisant, surtout quand on a besoin de tester que notre application s'intègre effectivement bien avec un webservice d'un de nos fournisseurs... Parlons de tests d'intégration, donc.
Qu'est ce q'un test d'intégration ?
De mon point de vue, un test d'intégration sert à tester l'intégration (ca paraît trivial mais il est important de le rappeller).
Je ne pense donc pas qu'il soit nécessaire de tester TOUTE l'application, ou TOUTES les fonctionnalités de l'application, ou toutes les lignes de code de l'application grâce aux tests d'intégrations, mais uniquement que les "intégrations" (i.e. "les communications / intéractions de notre code avec un autre code que nous n'avons pas développé") qui sont effectivement réalisées dans notre application.
Lister et catégoriser les intégrations
Il faut donc commencer à lister les "intégrations" de notre application. Elles peuvent être multiples :
- utilisation de base de données type SQL
- utilisation de webservices (soap, rest, xml, http, ...)
- import / export de fichiers
- intéractions avoir d'autres applications grâces à des protocoles non web standard ou propriétaire (ssh, ftp, scp, cft, ldap...)
et pour les plus puristes d'entre nous :
- utilisation du système de fichier
- utilisation de toute fonction native à la plateforme ayant un impact sur le système ou l'éco-système (réseau, disque, mémoire vive...)
- utilisation de librairies spécifiques (génération de pdf, génération d'images et de graphiques...)
En résumé, une "intégration" concerne l'utilisation de tout code ou librairie que vous N'AVEZ PAS développé vous même et qui est utilisé par votre application.
On peut les classer en deux types d'intégration :
- les intégrations distantes : i.e. "ressources utilisées / accédées via un protocole réseau", sont les plus "visibles" et facile à tester, elles concernent les utilisations de ressources externes telles que des webservices ou du ldap par exemple.
- les intégrations locales : i.e. "API intégrées dans le langage du code développé", sont les plus vicieuses et les plus difficile à tester, elles concernent l'utilisation de librairies (notamment PHP), d'extension / module, de framework, de ressources locales (disque dur, mémoire vive...)
Les types de tests d'intégration
Basiquement, on distingue 2 types de test d'intégration :
- les tests qui coûtent cher (long ou financièrement coutêux)
- les tests qui ne coûtent pas cher (rapide et sans / peu d'impact notable sur notre éco-système)
Une chose est sûr, tout test d'intégration qui est (facilement) automatisable doit être automatisé.
Attention cependant, en fonction du type de test (cher / pas cher), on peut décider d'exécuter régulièrement ou non le test d'intégration, tout n'est pas nécessairement candidat à l'exécution régulière (imaginez un test d'envoi de bulk massif de 100 sms via un broker, cela pourrait vite vous coûter cher en temps (lire les 100 sms) et en argent (à 0,07 centimes minimum le sms, ca fait quand même 7€ par exécution du test qui partent en fumée !, imaginez si vous exécutez ce test automatiquement à chaque commit, cela va vite vous faire mal d'appuyer sur le bouton "commit" !).
De mon point de vue, il y a donc une différence entre automatisation et exécution régulière. Je distingue donc 3 niveaux d'automatisation de tests d'intégration :
- test d'intégration manuel : i.e. procédure de contrôle décrite mais réalisée manuellement (via des clics et des saisies clavier par exemple)
- test d'intégration semi-automatique : i.e. test qui a été codé, est reproductible et déclenchable via un programme pré-programmé, mais nécessite une action humaine comme déclencheur. L'action humaine peut être un clic, une commande console à exécuter ou une url à appeller via un navigateur, par exemple.
- test d'intégration automatique : i.e. idem semi-automatique mais déclenché sans l'intervention de l'homme par un évènement pré-programmé (ex: commit subversion, build nocturne ...)
"Quel outil choisir pour mes tests d'intégration ?" où la question dont la réponse n'est pas (la plus) importante
Je vous voit tous à attendre avec une impatience une liste d'outils populaires pour rédiger et exécuter vos tests d'intégrations. Donc, la voici !
- PHP.
Trève de plaisanterie, de mon point de vue, le vrai sujet au-delà de la question de savoir si vous allez pouvoir utiliser tel ou tel outils meilleur que son voisin pour vos tests d'intégrations, est plutôt de savoir et de comprendre les enjeux des tests d'intégration, et les problèmes que vous allez devoir résoudre.
Je vous conseille d'utiliser des outils que vous maîtrisez et qui permettent de faire des rapports d'erreurs d'exécutions tels que les outils de type xUnit (PHPUnit, voire SimpleTest) qui sont adaptés pour exécuter du code PHP et faire un rapport sur des assertions bonnes ou fausses sur le résultat.
Les contexts d'intégration : où le niveau de cloisonnement des tests
Qu'est ce qui se cache derrière le terme barbare de "cloisonnement des tests d'intégrations" ? Tout simplement le niveau d' "impact" que vous avez sur l'application avec laquelle vous êtes intégré, on peut en effet distinguer différents niveaux d'impact en fonction des environnements mis à disposition pour l'intégration :
- bouchon local : cloisonnement total car pas de persistence côté application distante, mais vous devez installer localement et avec vos compétences le bouchon éventuellement fourni par l'équipe de l'application à laquelle vous souhaitez vous intégrer
- bouchon distant : cloisonnement total car pas de persistence côté application distante
- environnement de test dédié : cloisonnement fort car votre application est la seule à appeler cette instance de l'application distante
- environnement de test mutualisé : cloisonnement faible mais impact minime (instance de test)
- environnement de préproduction : cloisonnement faible voir inexistant mais impact non critique (instance de préproduction)
- environnement de production : aucun cloisonnement, impact maximal (instance de production)
- ...
Plus vous aurez un cloisonnement fort, plus vos tests seront faciles et peu coûteux pour une exécution (très) régulière, et inversement.
L'idée reçue : un test d'intégration est un test de bout en bout graphique ou fonctionnel
Il sera toujours plus difficile d'automatiser (et de rejouer régulièrement) le test de bout en bout qui vise à vérifier que la valeur 2 est bien présente dans la case 3 du tableau de la deuxième page (sachant que la valeur 2 est récupérée via un appel de webservice) plutôt que d'appeller en direct le webservice via une API développée dans votre code.
Attention donc, de mon point de vue un test d'intégration n'est pas un test bout en bout graphique ou fonctionnel, mais plutôt un moyen de tester que les couches basses de votre application savent communiquer avec l'application distante selon le ou les contrats de services définis.
L'API locale : La clé pour rédiger facilement vos tests d'intégration
Pour tester "uniquement" l'intégration, il faut donc privilégier le développement d'API interne à votre code qui permet de "cacher / envelopper" l'appel à l'application distante à laquelle vous vous intégrée. Ce qui vous permettra de facilement développer des scripts php de tests d'intégration en utilisant PHPUnit par exemple.
Cette API locale devra fournir l'"enrobage" de l'appel à l'application distante en fournissant à votre code des fonctionnalités "locales" faciles à utiliser et faciles à bouchonner (notamment pour vos tests unitaires).
Ainsi lors de vos développements, vous devriez à minima avoir 2 types de fonctions / méthodes / classes :
- les fonctions / méthodes / classes du coeur de votre application
- les fonctions / méthodes / classes fournissant une API d'accès aux applications et fonctionnalités distantes à intégrer
Une fois développé cette couche / API locale, il vous sera plus facile de réaliser des scripts PHP de tests d'intégration utilisant cette API en direct et manipulant l'API pour tester les différentes fonctionnalités disponibles.
Une piste pour la réalisation de cette API locale serait la création systématique d'une classe <ApplicationAIntegrer>Service qui fourni les différentes fonctionnalités à intégrer sous forme de méthode, et de créer pour ce service un adapter sous-jacent par défault (réalisant effectivement les appels distants) et à minima un adapter bouchon (mock) utile pour les tests unitaires par exemple et le développement. Je vous invite à lire mes billets sur le concept de service et d'adapter pour plus de précision et d'exemple sur comment s'y prendre en PHP via un exemple.
Cette technique d'API locale (peu importe le protocole réseau ou non) est systématiquement utilisée par les grands fournisseurs de webservices de nos jours (eBay / PayPal / Google ...) avec de plus en plus une intégration dans les frameworks populaires alla Zend Framework ou Symfony.
Où placer mes tests d'intégrations ?
Dans le répertoire locale de votre application : ./tests/integration, par exemple ;)
Vous pouvez créer un répertoire par "intégration" et un fichier par cas de test d'intégration, ou bien si vous utilisez PHPUnit par exemple, une classe de test par "intégration" et une méthode de test par cas d'intégration.
Pour la suite, à vous de me dire ce que vous voulez...
Je vais m'arrêter là pour l'instant, si vous souhaitez des précisions ou des exemples sur des aspects ou des points concrets, vous n'avez qu'à demander ;)
Et sinon, vous comment faite vous pour écrire vos tests d'intégration ?
PS: Bien sûr il manque encore au moins un test, le test de bout en bout ;)
Commentaires
merci pour cette article, c'est intéressant de trouver des sujets qui touche le monde professionel en plus autour de PHP. Ce qui est rare.
Mais c'est vrai qu'avoir des exemples concret c'est encore mieux. aussi je suis preneur