Contactez-nous
Kitpages
17 rue de la Frise
38000 Grenoble
tel : 04 58 00 33 81
Des tests fonctionnels dans Symfony 2 grâce à Behat et Mink
Introduction
Ce tutoriel est réalisé avec la v2.3.7 de Symfony
Toutes les commandes sont exécutées depuis la racine du projet.
Installer les vendors
Ajouter dans le composer.json puis exécuter un composer update
"require-dev": {
"behat/behat": "2.5.1",
"behat/symfony2-extension": "v1.1.0",
"behat/mink": "v1.5.0",
"behat/mink-extension": "v1.2.0",
"behat/mink-browserkit-driver": "v1.1.0",
"behat/mink-zombie-driver": "dev-master"
}
Configuration
Créer le fichier behat.yml à la racine du projet, contenant le code suivant
- base_url : adresse d'accès à l'environnement symfony de test, (créer le fichier app_test.php qui va bien à partir du app_dev.php - doc officielle)
default:
extensions:
Behat\Symfony2Extension\Extension:
mink_driver: true
Behat\MinkExtension\Extension:
default_session: 'symfony2'
base_url: http://4000m.test/
Initialiser les features
Avec la commande suivante, on initialise le répertoire des futures features pour un bundle donné. (ici, DemoBundle de l'application Acme)
# pour initialiser les tests d'une appli complète bin/behat --init # pour initialiser les tests dans un bundle bin/behat --init @AcmeDemoBundle
Lancer les tests
# Pour lancer les tests de l'appli complète si vous n'avez pas initialiser dans les bundles ./bin/behat # Pour lancer les tests d'un bundle en particulier ./bin/behat @AcmeDemoBundle # Pour lancer les tests de tous le projet ./script/behat.sh
Le fichier behat.sh
#!/usr/bin/env bash
NORMAL="\\033[0;39m"
BLEU="\\033[1;34m"
__DIR__="$(cd "$(dirname "${0}")"; echo $(pwd))"
__FILE__="${__DIR__}/$(basename "${0}")"
__ROOTDIR__=$(dirname ${__DIR__})
__APPDIR__=$(dirname ${__DIR__})/app
__SRCDIR__=$(dirname ${__DIR__})/src
BEHAT="./bin/behat"
APPCONSOLE="./app/console"
question() {
local question=$1
local choices=$2
local default=$3
echo -en "\n" "$BLEU" "== $question (${choices}) [${default}] " "$NORMAL"
read RESPONSE
if [ "x$RESPONSE" = "x" ]; then
RESPONSE=$default
fi
}
question "Supprimer et recréer la base de données ?" "y|n" "n"
if [ "x$RESPONSE" = "xy" ]; then
question "WARNING : Êtes-vous sûr de vouloir supprimer et recréer la base de données ?" "yes|no" "no"
if [ "x$RESPONSE" = "xyes" ]; then
$APPCONSOLE doctrine:database:drop --force --env=test
$APPCONSOLE doctrine:database:create --env=test
fi
fi
question "Clôner la bdd de dev pour les tests ?" "y|n" "n"
if [ "x$RESPONSE" = "xy" ]; then
echo -en "---> db host [127.0.0.1] : "
read DB_HOST
if [ "x$DB_HOST" = "x" ]; then
DB_HOST="127.0.0.1"
fi
echo -en "---> db user [root] : "
read DB_USER
if [ "x$DB_USER" = "x" ]; then
DB_USER="root"
fi
echo -en "---> db password [] : "
read -s DB_PASS
if [ "x$DB_PASS" = "x" ]; then
DB_PASS=""
fi
echo -en "---> db name src [appsandbox_dev] : "
read DB_NAME_SRC
if [ "x$DB_NAME_SRC" = "x" ]; then
DB_NAME_SRC="appsandbox_dev"
fi
echo -en "---> db name dest [appsandbox_test] : "
read DB_NAME_DEST
if [ "x$DB_NAME_DEST" = "x" ]; then
DB_NAME_DEST="appsandbox_test"
fi
mysqldump -h $DB_HOST -u $DB_USER -p$DB_PASS $DB_NAME_SRC | mysql -h$DB_HOST -u $DB_USER -p$DB_PASS $DB_NAME_DEST
fi
question "Vérifier la validité du schéma ?" "y|n" "n"
if [ "x$RESPONSE" = "xy" ]; then
$APPCONSOLE doctrine:schema:validate --env=test
fi
question "Consulter les modifications du schéma avant la mise à jour ?" "y|n" "n"
if [ "x$RESPONSE" = "xy" ]; then
$APPCONSOLE doctrine:schema:update --env=test --dump-sql --complete
fi
question "Mettre à jour le schéma ?" "y|n" "n"
if [ "x$RESPONSE" = "xy" ]; then
$APPCONSOLE doctrine:schema:update --env=test --force --complete
fi
question "Ajouter des données depuis les fixtures doctrine ?" "y|n" "n"
if [ "x$RESPONSE" = "xy" ]; then
$APPCONSOLE doctrine:fixtures:load --append --env=test
fi
question "Créer un compte fos admin ?" "y|n" "n"
if [ "x$RESPONSE" = "xy" ]; then
echo -en "---> admin login [admin] : "
read ADMIN_LOGIN
if [ "x$ADMIN_LOGIN" = "x" ]; then
ADMIN_LOGIN="admin"
fi
echo -en "---> admin email [test@hotmail.com] : "
read ADMIN_EMAIL
if [ "x$ADMIN_EMAIL" = "x" ]; then
ADMIN_EMAIL="test@hotmail.com"
fi
echo -en "---> admin password [] : "
read ADMIN_PASSWORD
if [ "x$ADMIN_PASSWORD" = "x" ]; then
echo "the admin password is mandatory";
exit;
fi
$APPCONSOLE fos:user:create $ADMIN_LOGIN $ADMIN_EMAIL $ADMIN_PASSWORD -env=test
$APPCONSOLE fos:user:promote $ADMIN_LOGIN ROLE_ADMIN --env=test
fi
question "Insérer les uploads depuis l'archive tar.gz ?" "y|n" "n"
if [ "x$RESPONSE" = "xy" ]; then
cd ./web
tar zxvf ../app/Resources/docs/uploads.tar.gz
cd -
fi
question "Lancer tous les tests en une fois ?" "y|n" "y"
if [ "x$RESPONSE" = "xy" ]; then
for app in `ls $__SRCDIR__`; do
for bundle in `ls $__SRCDIR__/$app`; do
if [ -d $__SRCDIR__/$app/$bundle/Features ]; then
$BEHAT @$app$bundle
fi;
done;
done;
else
for app in `ls $__SRCDIR__`; do
for bundle in `ls $__SRCDIR__/$app`; do
if [ -d $__SRCDIR__/$app/$bundle/Features ]; then
question "Lancer les tests de @$app$bundle ?" "y|n" "n"
if [ "x$RESPONSE" = "xy" ]; then
$BEHAT @$app$bundle
fi
fi
done;
done;
fi
echo -e "\nTerminé !\n"
Ecrire des tests
Pour écrire des scénarios web, il ne faut pas oublier de modifier la classe FeatureContext pour qu'elle étende le MinkContext à la place de BehatContex. Cette modification nous fera gagner du temps en donnant du sens à des phrases clés pour les étapes. (cf. Liens utiles)
Ci-dessous, un exemple simple d'un test web qui ne nécessitera aucun code supplémentaire.
Feature: Administration des réservations
Dans le but de gérer les réservations en tant qu'administrateur
Scenario: Un utilisateur peut se connecter à l'administration
Given I am on homepage
When I follow "login"
And I fill in "Zazou" for "Nom d'utilisateur"
And I fill in "123456" for "Mot de passe"
And I press "Connexion"
Then I should be on "/admin/catalogue/dropzone"
Donner du sens aux tests
Pour donner du sens au code écrit dans les tests et qui sortent du cadre de Mink, il faut alors coder les méthodes qui vont bien dans le FeatureContext.php correspondant. Petite astuce, pour accéder au container Symfony, il suffit de rajouter le trait KernelDictionary. Le container devient alors accessible depuis $this->getContainer(). Et par extension, on a accès aux services symfony.
<?php
// namespace ...
use Behat\Symfony2Extension\Context\KernelDictionary;
// ...
class FeatureContext extends MinkContext implements KernelAwareInterface
{
use KernelDictionary;
// ...
/**
* @Then /^an order was registered in database with status "([^"]*)"$/
*/
public function anOrderWasRegisteredInDatabaseWithStatus($arg1)
{
$container = $this->getContainer();
$doctrine = $this->getContainer()->get('doctrine');
// ...
}
}

Commentaires
Note : on ne peut plus ajouter de commentaire sur ce site