Vous connaissez sans doute les tests unitaires exécutés avec PHPUnit, Atoum ou autre… Il existe d’autres types de tests répondant à d’autres besoins comme les tests d’interface, les tests de charge (stress test), les tests de sécurité ou les tests fonctionnels. Je m’arrêterai plus spécialement sur ces derniers.
Pour les tests fonctionnels, le but est de tester l’application comme un utilisateur le ferait. Mais il y a plusieurs façons d’exécuter les tests :
C’est-à-dire en simulant les requêtes HTTP et en examinant les réponses sans utiliser un navigateur et un serveur web. Par exemple avec Symfony, cela consiste à générer un objet Request qui passe dans le kernel Symfony (par la fonction handle). Ce dernier retourne un objet Response qui est analysé par Behat.
Cette méthode de test est pratique quand vous n’avez pas de javascript à exécuter côté navigateur. C’est rapide, simple à mettre en place avec Behat et vous pouvez interagir avec le kernel Symfony avant, pendant et après le traitement de la requête. Ces tests ont un défaut : outre l’absence de l’exécution du javascript de plus en plus présent, c'est la possibilité de manipuler le kernel Symfony. Cela rend possible certains tests qui ne devraient pas être possibles introduisant alors, un biais lors des tests.
Cette méthode ajoute son lot d’outils car il est nécessaire de piloter un navigateur tel que Chrome, Firefox, Internet Explorer Edge selon vos prérequis.
Cela implique donc l’utilisation de Selenium ainsi que Behat avec Mink ou Panther pour PHP.
Grâce au navigateur, l'exécution du Javascript permet des tests plus poussés car il est possible d’utiliser la puissance du navigateur pour réaliser les tests souhaités. D’un autre côté, certains tests sont plus contraignants à réaliser car il n’est pas possible de modifier le kernel Symfony présent dans PHP-FPM côté serveur.
En utilisant tous ces outils, les tests sont plus lents à cause de l’empilement des outils et de l'augmentation de l'utilisation des ressources de la machine. Ce type de tests nécessite également l’ajout de fonctionnalités uniquement dédiées aux tests telles que des routes pour changer l’utilisateur du site, le by pass de l’authentification… Nous nous attacherons particulièrement dans ce billet à présenter les tests que j'ai réalisés avec Selenium.
Selenium est un outil de tests automatisés pour navigateur. La version 1 ou Selenium RC (Remote Control) injectait du code JavaScript dans le navigateur une fois lancé pour le piloter. Cette façon de faire avait de nombreuses limites (limitation au capacités du JavaScript, pas de possibilité de capture d'écran...). Pour ne plus utiliser l’injection du JS dans le navigateur, le projet WebDriver est né chez Google permettant un pilotage natif du navigateur.
Selenium 2 (ou Selenium-WebDriver) est la fusion de WebDriver et de Selenium 1 pour le meilleur des mondes. En effet, la fusion a permis à Selenium de piloter nativement les navigateurs et à WebDriver de pouvoir être exécuté sur les grappes de serveur, à distance, etc...
Dans notre cas, l'utilisation du langage PHP nous oblige à utiliser Selenium plus WebDriver. Certain langages tel que Java peuvent se passer de Selenium dans le cas où les tests sont exécutés sur un seul navigateur et en local.
Pour plus d’informations sur Selenium, je vous laisse visiter le site du projet : https://www.seleniumhq.org
Pour nos tests, la configuration est la suivante :
Sur le poste de développement, Vagrant est utilisé avec une machine virtuelle basée sur CentOS 6. L’application utilise PHP 7.1 et Symfony 2.8 (migration en cours vers des versions plus récente de Symfony et PHP).
Behat est déjà installé avec Mink et son extension MinkSelenium2Driver qui permet l’utilisation de Selenium.
Il est donc nécessaire de pouvoir exécuter les scenarii écrits via le navigateur Chrome ou Firefox. Par défaut, l’image dispose de FireFox 52 et Chrome n’est pas supporté pour CentOS 6.
Lorsque vous utilisez Selenium Server, il met à disposition une API HTTP permettant le pilotage du navigateur via le WebDriver. Cette API expose le dialecte géré par le WebDriver. Le dialecte historique est OSS et un nouveau dialecte standardisé par le W3C est en voie d’adoption. Ces deux dialectes ne sont pas complètement compatibles entre eux. Dans le cas de ChromeDriver, le dialecte W3C est maintenant celui par défaut. Il est donc nécessaire de le reconfigurer pour utiliser OSS lorsque vous utilisez MinkSelenium2Driver.
Après de nombreux déboires sur le non fonctionnement de Firefox sans fenêtre mais également parce que c’est une ancienne version, le choix a été fait d’utiliser Chrome même s’il n’est pas géré nativement par CentOS 6.
En fouillant un peu sur Internet, un script d’installation existe pour l’installation de la dernière version de chrome sur CentOS 6. Mais ce script n’installe pas le ChromeDriver et celui préconstruit par l’équipe de Selenium nécessite des librairies absentes de CentOS 6.
Le premier script a donc été modifié pour permettre également l’installation de ChromeDriver. Cependant, une dépendance posait problème et le souci a finalement été résolu manuellement. Voici le dernier script d’installation de Chrome et ChromeDriver sur CentOS 6.
Ce script installe toutes les librairies et les applications dans le dossier /opt/google/chrome.
Un lien symbolique doit être réalisé pour ChromeDriver dans /usr/bin afin qu’il soit là où l’attend Selenium.
Note: l’utilisation de Chrome et ChromeDriver nécessite que l’IPv6 soit activé sur votre machine.
Lorsque vous téléchargez Selenium Standalone Server, vous obtenez une fichier JAR. Pour l’exécuter il est nécessaire d’avoir Java 1.8 (ou OpenJDK 1.8) ou supérieur.
Vérifiez la version de java installé avec la commande "java -version"
S’il n’est pas installé ou si c’est une version antérieure, utilisez le gestionnaire de paquets de votre OS pour installer une version plus récente. Dans le cas CentOS 6, la commande suivante devrait vous aider : "yum install -y java-1.8.0-openjdk"
Maintenant, pour lancer Selenium, exécutez la commande suivante en étant dans le dossier contenant le fichier JAR :
java -jar selenium-server-standalone-3.141.59.jar
Le serveur démarre et ouvre le port TCP 4444 en écoute. Cependant, il est nécessaire de lancer manuellement le service et il bloque la console. L’avantage de ce mode de fonctionnement est pour le debug. Le log de Selenium sort sur la console rendant la lecture des logs directe.
Une fois mis en place, il est possible de démarrer Selenium en tant que service grâce à un script d’init à placer dans le dossier /etc/init.d/
#!/bin/bash
#chkconfig: 345 95 50
#description: Starts xvfb on display 99
if [ -z "$1" ]; then
echo "`basename $0` {start|stop}"
exit
fi
case "$1" in
start)
/usr/bin/java -jar /opt/selenium/selenium-server-standalone-3.141.59.jar > /var/log/selenium.log 2>&1 &
;;
stop)
killall java
;;
esac
Dans certain cas, il est nécessaire de debug le chrome driver. Vous pouvez le configurer au démarrage de Selenium avec les options suivantes :
-Dwebdriver.chrome.logfile=/var/log/chromedriver.log -Dwebdriver.chrome.verboseLogging=true
Note : Attention à ne pas avoir d'autres applications java en cours d'exécution sur le poste ou le serveur lors de l’arrêt de Selenium. Il peut y avoir des dommages collatéraux.
Maintenant que Selenium est a l’écoute sur le port TCP 4444, il est possible pour Behat et Mink de l’utiliser.
Pour cela, la configuration de Behat doit être modifiée pour configurer l’extension Selenium2Driver.
Voici un exemple de configuration :
default:
extensions:
Behat\MinkExtension:
base_url: http://monsupersite.local
browser_name: chrome
sessions:
default:
selenium2:
wd_host: http://localhost:4444/wd/hub
capabilities:
browser: chrome
chrome:
binary: '/opt/google/chrome/chrome'
switches:
- "--no-sandbox"
- "--headless"
- "--disable-gpu"
- "--start-maximized"
extra_capabilities:
chromeOptions:
w3c: false
La clé de configuration « wd_host » donne l’URL d’accès au serveur Selenium.
Le bloc de configuration « chrome » donne les informations sur l’emplacement du binaire de chrome sur le serveur et les options à ajouter à la ligne de commande pour lancer l’exécution du navigateur.
L’option --no-sandbox désactive la sandbox de chrome car il fonctionne avec l’utilisateur root. L’option --headless indique à chrome qu’il n’a pas d’écran pour l’affichage. L’option --disable-gpu désactive l’accélération matériel de la carte graphique.
Le bloc « extra_capabilities » permet d’ajouter de la configuration pour Selenium et le WebDriver. Ici la désactivation du dialecte w3c pour le ChromeDriver. Cependant, cette option ne sera pas prise en compte avec la version 1.3.1 du MinkSelenium2Driver. Un pull request (https://github.com/minkphp/MinkSelenium2Driver/pull/309) a été demandée pour que cette configuration soit prise en compte.
Vous pouvez utiliser la version en attente de fusion via la configuration composer de votre projet.
[Mise à jour du 2 octobre] La modification est maintenant fusionnée dans la branche principale (master) du projet.
Maintenant que les outils sont fonctionnels, vous pouvez passer à l’écriture des scenarii.
Pour le debug, il est important de pouvoir réaliser un diagnostic du navigateur. Pour cela, il est possible de réaliser une capture d’écran du navigateur et la stocker dans votre projet.
Le contexte RawMinkContext propose déjà la fonction "saveScreenshot" qui permet la sauvegarde de l’image écran. Cependant, si un scénario échoue, il semble intéressant d’avoir systématiquement une capture.
Pour cela, Behat intègre des hook. Ici le hook « AfterStep » est tout indiqué. La deux premières vérifications à réaliser sont si le driver courant est Selenium2 (la prise en charge des captures d’écran n’est pas la même selon les drivers) et si l’étape a échouée.
Si tel est le cas vous pouvez appeler la fonction parente « saveScreenshot » pour sauvegarde la capture là ou vous le souhaitez.
Voilà pour mon retour d’expérience, et vous quel est le vôtre avec Selenium ?
🎯 Nous relevons le défi de lancer un grand concours : Vous faire gagner un ...
How to dynamically calculate shipping costs? The official documentation that explains how to create shipping ...
How to create a new product attribute type in Ibexa Commerce
A la recherche d'un poste de travail temporaire ou permanent ? Vous recherchez un environnement ...
Après une découverte de surface d'Ibexa Commerce, entrons plus dans le détail pour comprendre son ...
Ibexa DXP propose un module pour gérer des produits pour la réalisation d'un site e-commerce. ...
Voici une présentation d'IbexaMailing, un module qui ajoute la gestion des newsletters à Ibexa. IbexaMailing est ...
C'est la dernière occasion de vous souhaitez le meilleur pour cette année 2024 et surtout ...
En ce début d'année, en ce mois de janvier, mois des grandes résolutions, dépensons moins!Prenez ...
🎯 Nous relevons le défi de lancer un grand concours : Vous faire gagner un ...
How to dynamically calculate shipping costs? The official documentation that explains how to create shipping ...
How to create a new product attribute type in Ibexa Commerce
A la recherche d'un poste de travail temporaire ou permanent ? Vous recherchez un environnement ...
Après une découverte de surface d'Ibexa Commerce, entrons plus dans le détail pour comprendre son ...
Ibexa DXP propose un module pour gérer des produits pour la réalisation d'un site e-commerce. ...
Voici une présentation d'IbexaMailing, un module qui ajoute la gestion des newsletters à Ibexa. IbexaMailing est ...
C'est la dernière occasion de vous souhaitez le meilleur pour cette année 2024 et surtout ...
En ce début d'année, en ce mois de janvier, mois des grandes résolutions, dépensons moins!Prenez ...