Comment mettre en place vos plateformes de tests automatisés en un clic grâce à Docker ?

Cet article reprend les éléments d’une présentation ALL4TEST réalisée à la soirée du test logiciel de Sophia-Antipolis en octobre 2017. Il abordera les tests automatisés dans le monde agile/devops , plateformes de tests automatisés avec Docker, Selenium Webdriver, Selenium Grid, Zalenium…

Les tests automatisés dans le monde Agile/Devops

L’agilité consiste à développer un produit logiciel par itération, en livrant au client à intervalles réguliers et courts une nouvelle version de l’application comportant à chaque fois des fonctionnalités supplémentaires.

Afin de garantir, à chaque itération, la livraison d’une version conforme en terme de qualité aux exigences du client, l’intégration des tests dans le processus de construction du logiciel doit se faire dès le démarrage du projet, et tout au long de sa réalisation: c’est le principe du test continu, qui s’appuie sur l’automatisation des tests, rendue indispensable par la nécessité de répéter un nombre de tests important à chaque nouvelle itération du logiciel.

 

Le test continu, grâce à l’automatisation, s’intègre dans le processus  de développement et de distribution des logiciels afin d’obtenir le plus rapidement possible des retours sur les risques associés à chaque nouvelle version. L’implémentation de tests automatisés  permet de faire face à la complexité et au rythme accrus de développement et de livraison d’applications.

L’application logiciel de nos jours est devenu la clé pour la création d’un avantage concurrentiel sur tous les marchés. Les entreprises par conséquent ne peuvent plus se contenter de choisir entre «vitesse» ou «qualité» lors de la livraison de logiciels.

Pour s’adapter à cette réalité, les entreprises ont dû intégrer méthode Agile et principes DevOps dans leurs pratiques, nécessitant de maîtriser à la fois intégration continue, livraisons continues, et test continu, cette dernière notion étant de loin la plus difficile à mettre en pratique.

En effet, l’intégration continue dépend principalement  des outils permettant son implémentation; la prestation continue s’appuie  sur les outils dédiés et sur les équipes de développement. Le test continu doit quant à lui mettre en œuvre à la fois des outils spécifiques, les équipes de développement, mais également des ressources et services côté client. Construire et intégrer rapidement des changements de code est certainement important. Toutefois, sans processus de livraison automatisé permettant de déterminer comment les changements affectent le risque commercial ou perturbent l’expérience de l’utilisateur final, la fréquence et la rapidité accrues de l’intégration continue et de la livraison continue peuvent devenir un passif plus qu’un actif.

Les tests automatisés dans les plateformes micro-services

Qu’est-ce qu’un micro-service ?

Un micro-service est une unité fonctionnelle qui correspond à une fonctionnalité précise. Un micro service est autonome, qui a son propre code et gère ses propres données.

Un micro-service peut être constitué de plusieurs processus mais l’inverse n’est pas vrai. Une conséquence directe est que les services communiquent entre eux par des appels réseaux et non pas des appels de fonction interne comme dans une application monolithique. Par conséquent, un micro-service est une unité de service qui se développe, se déploie, s’exécute et gère ses données indépendamment des autres services du système. Les avantages d’un système basé sur les micro-services sont, entre autres:

  • La modificabilité : pour implémenter une évolution précise sur le système, seul le code du micro service concerné doit être mis à jour puis redéployé;
  • Une architecture à l’échelle du service: Un micro service est un processus isolé, donc l’augmentation et la diminution des ressources allouées à un service ou à un ensemble de service se fait de manière isolée.

Les tests dans une architecture micro-service

Le test des applications basées sur les micro-services doivent être automatisés et associés au processus d’intégration et de déploiement (cf. approche de Production Continue ou « Continuous Delivery »). Un micro-service étant autonome et indépendant, il peut être déployé individuellement lorsque les tests sont concluants.

Les systèmes basés sur les micro services s’appuient généralement sur une architecture complexe, rendant particulièrement importants les tests d’intégration et les tests de bout en bout, dont l’automatisation s’avèrera alors particulièrement intéressante.

Automatiser les test d’intégration et les tests de bout en bout implique, pour la viabilité du système en production, que les déploiements soient au maximum automatisés – on parle alors de déploiement continu. Les procédures de déploiement doivent être reproductibles, et contenir le moins de sources d’erreurs possible – intervention manuelle notamment – car elles seront potentiellement jouées un grand nombre de fois.

Plateformes des tests automatisés avec Selenium

Selenium WebDriver

Pour le développement de tests automatisés d’application Web auprès de nos clients, nous avons opté pour la solution Selenium WebDriver. Consultez cet article si vous devez commencer avec Selenium WebDriver.

Elle contient une collection  d’API open-source qui sont utilisées pour automatiser le test d’une application Web. Disponible pour plusieurs langages, l’API permet de programmer des scripts d’actions à réaliser sur l’application Web directement dans le navigateur, pour en vérifier ensuite le comportement par inspection du document de la page Web.. Les actions à réaliser peuvent également être exportées depuis Selenium IDE.

WebDriver est basé sur un modèle client-serveur. Un client de test envoie des “commandes” via des requêtes HTTPS à un serveur WebDriver après initialisation d’une session. Ce dernier distribue alors les commandes auprès des drivers des navigateurs concernés. Ces drivers exécutent les commandes sur les navigateurs en question via des mécanismes de communication interne – système d’exploitation ou JavaScript.

Selenium Grid               

Afin de pouvoir lancer en parallèle des tests sur plusieurs machines différentes, Selenium dispose d’un mode Grid.

Il consiste à disposer d’un serveur “hub” qui répertorie les serveurs “node” disponibles pour l’exécution de tests, réceptionne les scripts de test de l’utilisateur, pour ensuite les transmettre et les faire exécuter – de façon transparente pour l’utilisateur – sur les serveurs “node”, en fonction de leurs caractéristiques propre (type et version du navigateur, OS, etc) et de leur disponibilité.

Problématiques :

L’exécution de tests sur des plateformes de tests automatisés Selenium Grid soulève néanmoins plusieurs problématiques:

  • La maintenance des serveurs;
  • La maintenance des navigateurs et OS sur chaque machine;
  • Une recherche de solution complexe lorsqu’apparaît un problème sur l’un des serveurs “node”
  • La mise à jour difficile de l’ensemble de la plateforme de test;
  • le caractère statique de l’infrastructure, qui n’est pas extensible;

Ces inconvénients inhérents à Selenium Grid empêchent une bonne adaptation aux exigences du monde Agile/Devops.

Solutions :

Une des solutions pour palier aux lacunes de la solution Selenium Grid seule est d’utiliser, comme couche logicielle complémentaire, un produit de conteneurisation du type Docker, pour obtenir alors une plateformes de tests extensible..

Pour obtenir une plateforme de test Selenium Grid extensible s’appuyant sur des conteneurs Docker, on peut utiliser:

  • directement les solutions Cloud proposées par des sociétés comme Saucelabs ou BrowserStack;
  • Configurer et utiliser des instances EC2 proposée par le service cloud d’Amazon Web Services.

Docker

C’est quoi Docker ?

Docker est une solution open-source (sous licence Apache 2.0) qui vise à automatiser le déploiement d’applications dans ce que l’on nomme des “containers”. Situé à mi-chemin entre la virtualisation applicative et l’automatisation (on parle aussi de virtualisation légère), le projet a été lancé officiellement en 2013 et il ne cesse depuis de gagner en popularité.

Les principes de Docker

L’utilisation des containers Docker repose sur trois principes :

  • Le noyau du système d’exploitation Linux (ou kernel);
  • Les cgroups « control groups » qui est une fonction du kernel permettant de gérer l’accès aux différentes ressources de la machine (processeur, espace disque, utilisation de la RAM, etc.)
  • les Linux Containers ou LXC. qui permettent une virtualisation au niveau système (car basé sur le kernel et les cgroups), permettant de faire fonctionner plusieurs systèmes Linux de façon isolée.

Les objectifs de Docker

 Les objectifs principaux de Docker sont:

  • Simplifier le déploiement des environnements avec des conteneurs portables et légers.
  • Créer des environnements (Conteneurs) de manière isolés de l’application.

Différence entre machine virtuelle et Docker

Grâce à Docker, il est possible de mettre en place des environnements isolés les uns des autres sur une même machine. Ce principe est similaire à celui d’une machine virtuelle, mais là ou une machine virtuelle isole tout un système d’exploitation, Docker, lui, permet de partager les ressources du système hôte, le kernel interagissant ainsi avec les différents environnements de Docker.

Avec Docker, le kernel est en mesure de partager les ressources de l’hôte et d’interagir avec les différents containers. Ainsi on comprend que Docker ne fonctionne pas comme une Virtual Machine mais permet d’offrir un environnement de travail virtuel. On parle alors de virtualisation légère pour Docker. Qui plus est, puisque le conteneur n’a pas besoin de faire tourner son propre système, il est moins gourmand en mémoire, plus facile à migrer et plus rapide à sauvegarder.

Les conteneurs peuvent interagir directement avec le matériel et les périphériques par l’intermédiaire des groupes, ce qui permet un accès direct aux ressources de la machine hôte, sans passer par une couche de virtualisation.

Docker est également très efficace pour déployer plus de containers. La différence en termes d’occupation par rapport à une VM peut être très significative.

 

Plateformes de tests automatisés avec Docker

L’utilisation de Docker permet de solutionner les problématiques de maintenance et d’extensibilité des plateformes de tests automatisés. Ce nouveau concept offre la possibilité de gérer les configurations d’OS et de navigateurs sur lesquelles exécuter des scripts de test de façon programmable.

Docker permet notamment de : 

  • Lancer automatiquement et à la volée des configurations spécifiques en terme de navigateurs et systèmes d’exploitation à partir d’image préparées à l’avance;
  • Configurer des combinaisons navigateurs / OS de manière programmée (Docker Compose)
  • Fonctionner avec beaucoup moins de ressources que des machines virtuelles;.
  • Créer une plateforme de test automatisé en quelques secondes.
  • Avoir une plateforme de test extensible au fur et à mesure de l’évolution de la demande en terme d’exécution de tests automatiques

Zalenium – extension de Selenium Grid

Présentation

 Zalenium est une extension de Selenium Grid permettant la mise en place locale et dynamique de plateformes de tests automatisés en utilisant des conteneurs Docker. Elle utilise Docker Sélénium pour exécuter des tests automatiques sur Firefox et Chrome localement, et redirige vers un fournisseur de tests cloud (Sauce Labs, BrowserStack, TestingBot) lorsqu’un script doit être exécuté sur un navigateur différent

Zalenium intègre aussi d’autres fonctionnalités supplémentaires afin de faciliter le monitoring des tests:

  • Enregistrement des logs et mise à disposition d’enregistrements vidéos au sein d’un Dashboard
  • Un live preview pour les tests en cour d’exécution.

Fonctionnement

Zalenium fonctionne de la façon suivante:

  1. Un hub Selenium démarre et écoute sur le port 4444.
  2. Un noeud Docker Sélénium se manifeste et s’enregistre auprès du hub.
  3. Si l’intégration d’une plateforme de test dans le cloud est activée, un nœud de proxy cloud pour prendre en charge un fournisseur de cloud (Sauce Labs, BrowserStack, TestingBot) s’enregistre sur le hub.
  4. Une requête de test est reçue par le Hub et les capacités demandées sont vérifiées par rapport à chacun des noeuds.
  5. Si docker-sélénium peut remplir les capacités requises, un conteneur est créé à la volée et la demande de test est mise en attente par le Hub pendant le temps de la création du nouveau nœud.
  6. Le Hub attend que le nouveau nœud se manifeste une fois créé et achemine alors la demande de test vers lui.
  7. Le test est exécuté et le conteneur est clôturé après achèvement du test.
  8. Si le serveur docker-sélénium ne peut pas répondre à la demande d’exécution de script de test (caractéristiques demandées différentes de celles requises), le script sera alors exécuté  par l’une des plateformes de test de cloud activée.

Exemple d’application

 

Pour le compte de l’un de nos client, nous avons pu mettre en place toute une infrastructure de test automatisé, en utilisant des outils et des méthodes qui doivent permettre une bonne maintenabilité des tests, ainsi que des possibilité d’évolution et d’extension importantes.

Pour cette mission nous avons choisi d’utiliser Java comme langage de programmation, puisqu’il correspond au langage natif de Selenium WebDriver, et qu’il permet de bénéficier des différents patterns de Java pour améliorer la qualité de nos tests automatisés.

Ainsi qu’évoqué plus haut, le plus grand défi à relever dans l’automatisation des tests est la difficulté à les maintenir dans le temps. Aussi pour répondre à cette problématique, nous avons mis en place différentes stratégies, parmi lesquelles l’utilisation du Page Object pattern, ou encore des pattern plus évolués comme le Screenplay pattern qui est une approche pour écrire du code de haute qualité pour les tests automatisé et qui est basés sur les principes du SOLID on peut citer à titre d’exemple, le Single Responsability principle ou le Open Closed principle.

Sur la base des explications fournies plus haut, nous avons opté pour une infrastructure de test basée sur Docker et son extension Zalenium, afin de nous donner plus de flexibilité et de mieux gérer nos ressources.

Afin d’intégrer les tests automatisés dans le pipeline de build et de test de chaque nouvelle branche séparément, nous nous sommes appuyés sur Jenkins et avons créé des jobs dont l’exécution a servi à valider en continu les améliorations apportées à chaque étape de développement du projet.

Jenkins permet en effet:

  • de sélectionner et de lancer les images Docker correspondant aux configurations de tests à réaliser,
  • d’exécuter les scripts automatisés de test sur ces différentes images – correspondant à différents environnements et/ou navigateurs –
  • et enfin de générer un rapport d’exécution Cucumber interprétable avec Jenkins.

Zalenium permet quant à lui de disposer d’un confort d’utilisation supplémentaire, au travers du dashboard pour superviser les résultats de test, et de la fonctionnalité d’enregistrement vidéo des tests.