Cet article est un retour d'expérience sur la migration de tests fonctionnels Symfony classiques (utilisant les composants BrowserKit et DomCrawler) vers le nouveau composant Symfony Panther.
Les avantages de Panther
Les tests fonctionnels classiques sont une simulation de requêtes et de réponses en instanciant des objets PHP (Request et Response). S'il y a des soucis de chargement des ressources web, du JavaScript qui ne fonctionne pas par exemple, ces tests ne les repéreront pas.
Panther quant à lui, utilise un client PHP qui implémente le protocole WebDriver. Les tests vont se réaliser sur un vrai navigateur. On peut donc tester réellement ce qui se passe, et notamment le JavaScript. Actuellement, seul un driver Chrome est disponible.
Installation sur Docker
Il faut ajouter les lignes ci-dessous dans le Dockerfile de l'image contenant PHP :
# Installation pour Symfony Panther
RUN apt-get install -y libzip-dev zlib1g-dev chromium
# To disable Chrome's sandboxing (unsafe, but allows to use Panther in containers)
ENV PANTHER_NO_SANDBOX 1
Il faut également l'extension PHP zip. Si elle n'est pas déjà présente dans l'image, il faut la rajouter :
RUN apt-get install -y php7.3-zip
Il faut ensuite reconstruire l'image PHP.
Modification des tests fonctionnels existants
Il faut modifier toutes les classes parentes des classes de tests qui utilise WebTestCase, en mettant à la place PantherTestCase.
Par exemple, la classe :
namespace Tests\App\Controller\Front;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
/**
* Class ArticleControllerTest.
*/
class ArticleControllerTest extends WebTestCase
{
[...]
}
Devient :
namespace Tests\App\Controller\Front;
use Symfony\Component\Panther\PantherTestCase;
/**
* Class ArticleControllerTest.
*/
class ArticleControllerTest extends PantherTestCase
{
[...]
}
2ème étape, il faut modifier la méthode utilisée pour créer un client. Il faut le faire pour toutes les classes de tests qui créent un client.
Avant :
$client = static::createClient();
Après :
$client = static::createPantherClient();
Et c'est tout pour l'instant ! Il suffit alors de relancer les tests :
./bin/phpunit
En fonction de comment ont été écrits les anciens tests, il y aura plus ou moins des erreurs.
Correction des anciens tests
Si la récupération des services avec l'ancien client se faisait grâce à la méthode getContainer() :
$client->getContainer()->get('doctrine.orm.entity_manager');
Cette façon de faire ne fonctionne plus, le message d'erreur ci-dessous va apparaitre :
Error: Call to undefined method Symfony\Component\Panther\Client::getContainer()
Il faut maintenant accéder directement au conteneur :
self::$container->get('doctrine.orm.entity_manager');
Si les anciens tests utilisaient l'objet Response du composant HttpFoundation, l'erreur ci-dessous va apparaitre :
LogicException: HttpFoundation Response object is not available when using WebDriver.
Il ne faut plus accéder à l'objet Response dans les tests. Par exemple, le code ci-dessous n'est plus possible :
$client->getResponse()->isSuccessful();
C'est également le cas avec l'objet Request.
Panther utilise un client PHP qui implémente le protocole WebDriver. Ce protocole ne permet pas de récupérer le code de retour d'une requête HTTP. Donc à la place de vérifier un code de retour, il faut regarder par exemple qu'un élément de la page attendue soit bien affiché.
En conséquence, la méthode pour connaitre l'URL courante à changer. Avant :
$client->getRequest()->getUri();
Après :
$client->getCurrentURL();
Une fois les corrections effectuées, il faut relancer l'ensemble des tests jusqu'à obtenir 100% de succès.
Bonus
Avec Panther, on peut prendre une capture d'écran de manière très simple :
$client->takeScreenshot('mon_screenshot.png');
L'image est sauvegardée à la racine du projet. Elle permet de trouver plus facilement pourquoi un test est en erreur.
Version
Cet article a été testé avec :
Symfony : 4.2
PHP : 7.3
PHPUnit : 6.5