Download - Des tests modernes pour Drupal
Des tests 'MODERNES' pour Drupal
Christophe Villeneuve@hellosct1
Qui... est Christophe Villeneuve ?
<<
afup – lemug.fr – mysql – mariadb – drupal – demoscene – firefoxos – drupagora – phptour – forumphp – solutionlinux – demoinparis – ici et maintenant – eyrolles – editions eni – programmez – linux pratique – webriver – phptv – neuros - elephpant
Support présentation aujourd'hui
Disponible sur http://www.eyrolles.frDrupal avancé – un CMS pour développeurs par Christophe Villeneuve et Vanessa Kovalsky David aux Editions EYROLLES
Expérience sur... Les tests
✔ « Des fois cela plante »
Citations
✔ « On a testé, …
il y a 3 mois lors de la dernière livraison...
Pas eu le temps... »
L'importance des tests
✔ Le code peut casser
✔ Changer le nom d'un fichier
✔ Pas le temps d'en faire
✔ C'est long manuellement
Pourquoi c'est utile ? Et L'intérêt...✔ Coûte du temps au début
✔ En fait gain après
✔ Nécessite de la rigueur et de la constante
Les différents types de tests
Tests Unitaires● Module / classe / méthode
Tests fonctionnels● l'interface utilisateur testée par le client
Tests intégrations● Tester la navigation, et l'interface utilisateur
Tests Automatisés
Tests de charges
Tests d'ergonomie
Tests de sécurité
Tests unitaires... En pratique
Tests unitaires
✔ Existe-t-il ?
✔ Ecrire un test qui échoue
✔ Ecrire un test qui est bon
✔ Un test de sécurité
✔ Un test de contrôle
Déroulement Quoi tester ?✔ Un module
✔ Une classe
✔ Une méthode
✔ Tester✔ Ce qui est important✔ Le risque de casser✔ Les parties que vous
touchez souvent
Tests unitaires : Les API
✔ jUnit
✔ SimpleTest
✔ Zend_test
✔ PHPUnit
✔ Atoum
✔ ...D8D7 D9
SimpleTest
PHPUnit
Roadmap
Cas pratique avec PHPUnit
InstallationEn ligne de commandes
# sudo apt-get install phpunit
# pear channel-discover pear.phpunit.de
# pear channel-discover components.ez.no
# pear channel-discover pear.symfony-project.com
En mode assistée
- Windows
- Linux
- Mac
Avec IDE
- Eclipse PDT
- Netbeans
Tests unitaires : cas 1
<?php
class calculs
{
public function add($a, $b)
{
return $a + $b;
}
}
?>
<?php
class calculs
{
/**
* @assert (0, 0) == 0
* @assert (0, 1) == 1
* @assert (1, 0) == 1
* @assert (1, 1) == 2
* @assert (1, 2) == 3
*/
public function add($a, $b)
{
return $a + $b;
}
}
?>
Du code... +ieurs commentaires
Tests unitaires : cas 1
<?php
class calculs
{
/**
* @assert (1, 1) == 2
*/
public function add($a, $b)
{
return $a + $b;
}
}
?>
<?php
/**
* Generated from @assert (1, 1) == 2
*/
public function testAdd()
{
$this->assertEquals(
2,
$this->object->add(1, 1)
);
}
?>
1 commentaire Passer au test
Fonctionnement PHPUnit avec Drupal
✔ Boostrap✔ Script d'amorcage✔ Construction autonome
✔ Etendre le Boostrap✔ Emplacement du fichier✔ Déclarer les SLASHs✔ Recherche de racine Drupal✔ Chargeons boostrap.inc✔ Execution
PHPUnit avec Drupal : Comprendre
<?php
define('DRUPAL_ROOT', realpath(dirname(__FILE__) ) . DS );set_include_path(DRUPAL_ROOT . get_include_path());
include_once DRUPAL_ROOT . 'includes' . DS . 'bootstrap.inc';drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
class base_test extends PHPUnit_Framework_TestCase{ public function test_one_more_one_is_two() { $this->assertEquals(1+1,2); }}
?>
Résultat
. Le test est réussiF l'assertion a échouéE Erreur ExécutionS Problème inconnu I Test incomplet
Module & PHPUnit & Drupal
Module & PHPUnit & Drupal (1/2)
<?php
/**
* Implementation hook_help()
*/
function drupalcampmontreal_help($path, $arg) {
switch ($path) {
case 'admin/help#drupalcampmontreal':
$output = '<h3>A propos de : DrupalCamp Montréal</h3>';
$output .= '<p>Exemple de module test DrupalCamp Montréal 2014</p>';
return $output;
}
}
✔
drupalmontreal.module
Module & PHPUnit & Drupal (2/2)
<?php
include_once DRUPAL_ROOT . 'includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
class drupalcampmontreal_test extends PHPUnit_Framework_TestCase
{
public function test_function_help()
{
$output = '<h3>A propos de : DrupalCamp Montréal</h3>';
$output .= '<p>Exemple de module test DrupalCamp Montréal 2014</p>';
$this->assertEquals(drupalcampmontreal_help('admin/help#drupalcampmontreal'), $output );
}
...
drupalcampmontreal.test.php
Résultat
Tests Fonctionnels... En pratique
Tests Fonctionnels
✔ Prépare outil & API✔ Vérifie l'intégration des
différents composants
✔ On le partage
✔ On récupère le résultat
Déroulement Quoi tester ?✔ Nous... Rien
✔ C'est le client
Tests Fonctionnels : utilisation
✔ Selenium
✔ Casper.js & Phantom.js
✔ Cucumber
✔ GreenPepper
✔ ...
Outils
D8D7 D9
Selenium
Casper.js
Roadmap
Phantom.js
Cas pratique avec Selenium
Tests Fonctionnels : utilisation
Différents Selenium
● Selenium *.jar
● Selenium IDE– Extension Firefox
● SeleniumHQ– Compatible avec tous les navigateurs
http://www.seleniumhq.org/
Utilisation de Selenium
Selenium seul
Selenium et Drupal
✔ Module selenium
✔ S'appuie sur SimpleTest
Selenium pour PHPUnit
Installation PHP Unit & Selenium
# sudo apt-get install phpunit
# sudo apt-get install php5-curl
# sudo apt-get install php-selenium
En mode assistée
- Windows
- Linux
- Mac
Avec IDE
- Eclipse PDT
- Netbeans
Utilisation PHP Unit & Selenium (1/2)<?php
class TestLogin extends PHPUnit_Extensions_Selenium2TestCase {
public function setUp()
{
$this->setHost('localhost');
$this->setPort(4444);
$this->setBrowser('firefox');
$this->setBrowserUrl('http://localhost/seleniumTut');
}
public function testHasLoginForm()
{
$this->url('index.php');
$username = $this->byName('username');
$password = $this->byName('password');
$this->assertEquals('', $username->value());
$this->assertEquals('', $password->value());
}
Utilisation PHP Unit & Selenium (2/2)<?php
public function testSubmitButtonIsDisabledUntilFieldsAreFilled()
{
$this->url('index.php');
$username = $this->byName('username');
$password = $this->byName('password');
$submit = $this->byId('submit');
$this->assertFalse($submit->enabled());
$username->value('votreLogin');
$password->value('votrePassword');
$this->assertTrue($submit->enabled());
$username->clear();
$password->clear();
$username->value(' ');
$this->assertFalse($submit->enabled());
}
?>
PHPUnit / Selenium / Drupal (1/3)
PHPUnit / Selenium / Drupal (2/3)<?php
class drupalcampmontreal_test extends PHPUnit_Extensions_Selenium2TestCase {
public function setUp()
{
$this->setHost('localhost');
$this->setPort(4444);
$this->setBrowser('firefox');
$this->setBrowserUrl('http://localhost/drupal7');
}
public function testSite()
{
$this->setBrowserurl ('index.php');
}
PHPUnit / Selenium / Drupal (3/3)public function testOuverturePageTypeMenu() {
$this->open (
"http://localhost/drupal-test/admin/menus/diner" );
$this->assertElementValueEquals ( 'name', '' );
$this->assertElementValueEquals ( 'listlieu', '' );
}
Au final... les tests associés$ cd votreSite
$ phpunit sites/all/modules/menus/menus.test.php
Tests Intégrations... En pratique
Tests Intégrations
✔ 1 Navigation de la prod.
✔ Générer le script pour repérer les modifications de comportement
✔ 1 exécution sur le nouveau serveur
Déroulement Pourquoi ?✔ Simulation d'un être
humain
✔ Détection des problèmes éventuels
Tests Intégrations : utilisation
✔ Selenium
✔ Sikuli
✔ Hudson / Jenkins
✔ PhpUnderControl
✔ Behat/Mink
✔ Sahi
✔ PHPCov
✔ ...
Outils
D8D7 D9
Selenium
Behat+mink
Roadmap
Cas pratique avec Behat
Utilisation
# pear channel-discover pear.symfony.com
# pear channel-discover pear.behat.org
# pear install behat/behat
http://docs.behat.org/
{ "require": { "behat/behat": "2.4.*@stable" }, "minimum-stability": "dev", "config": { "bin-dir": "bin/" }}
ContexteEvénementsRésultat
Utilisation par le code Behat/Mink require_once 'mink/autoload.php';
class FeatureContext extends Behat\Mink\Behat\Context\MinkContext {
/** * @Given /^Je suis identifie "([^"]*)"$/ */public function jeSuisIdentifie($username){ return array( new Step\Given('I go to "login.php"') ,new Step\When("I fill in 'Mon nom' with '$username' ") ,new Step\When("I fill in 'Mon mot de passe' with '$password' ") ,new Step\When('I press "Login"') );}
}
Behat / Mint / Drupal (1/3)
Module behat
# curl -s https://getcomposer.org/installer | php
# php composer.phar install
# wget http://selenium...../selenium-server-standalone-2.26.0.jar
default:
context:
extensions:
Behat\MinkExtension\Extension:
base_url: 'http://localhost'
goutte: ~
selenium2: ~
Behat.yml
Behat / Mint / Drupal (2/3)
menus.featureScenario: Submits diner when required fields are filled out Given I am on "/" When I follow "diner" And I fill in "Your name" with "#name" And I fill in "Your lieu" with "#lieu" And I press "add" Then I should see "diner ajouter"
Behat / Mint / Drupal (3/3)
$ bin/behat features/menus.feature
© http://drupalwatchdog.com/volume-2/issue-2/behat-and-mink
Les autres Tests ….
Ils seront abordés dans la journée
Ils seront abordés dans la journée