SlideShare a Scribd company logo
1 of 38
Download to read offline
Mais en vrai on test quoi ?
Drupalcamp Lannion 2017
27/10/2017
Présentation sous licence CC 4.0 BY-SA-NC par Artusamak
Le point de départ
Je vais tout retester
Sarah, chef de projet
Et si on se concentrait sur la valeur ajoutée ?
Un projet parfaitement adapté aux tests
● Une base de code enrichie depuis 3 / 4 mois
● Du contenu et des utilisateurs existants (site déjà en prod)
● Des fonctionnalités limitées
● 2 développeurs sur le projet
Tests à disposition
Différents types de tests automatisables
● Tests unitaires
● Tests d’intégration
● Tests fonctionnels
● Tests de montée en charge
● Tests d’accessibilité
● Tests de régressions
● Tests de sécurité
● ...
Tests unitaires
● PHPUnit / UnitTestCase
● Tests rapides et autonomes (pas d’initialisation de base de données, peuvent
être lancés depuis PHPStorm ❤)
● Exemple : si je charge une permission depuis un YAML, j’ai bien un titre, une
description.
● On s’appuie sur des Mockups pour simuler les données d’entrées afin
d’augmenter les performances.
● Utile pour tester vos services ou vos classes utilitaires.
Tests d’intégration
● PHPUnit / KernelTestBase
● Permet d’accéder aux fonctions d’API de Drupal
● Se lance à partir d’une base vide (sans contenu) en RAM (peuvent être
initialisés à partir d’artefacts)
● Exemple : En chargeant la définition d’une propriété (base field) les
méthodes isReadOnly(), isComputed(), isTranslatable() me
renvoient bien les valeurs du schéma.
Tests fonctionnels
● Dépréciées : WebTestBase & KernelTestBase
● BrowserTestBase
● Drupal entièrement installé depuis un profil d’installation
● Très lent mais facile à écrire
● Exemple : Une vue m’affiche seulement les contenus pour lesquels j’ai une
permission
● A privilégier pour valider des comportements liés au rendu
Tests fonctionnels
● JavascriptTestBase
● Basé sur Mink + PhantomJS
● Un vrai navigateur web à disposition
● Interactions type drag’n drop
● Sert pour tester le JS du site de prod
● Exemple : Génération du nom machine d’un champ
Tests fonctionnels
● Behat
● Test des fonctionnalités utilisateurs en écrivant des scénarios
● S’écrit en langage naturel
● S’appuie sur une bibliothèque d’instructions
● Pas fait pour tester du code
● Décrit des comportements attendus
Mise en place de behat
Outillage
Behat 3 + Drupal extension
https://www.drupal.org/project/drupalextension
https://github.com/jhedstrom/drupalextension
https://github.com/jhedstrom/DrupalDriver
$ composer require drupal/drupal-extension='~3.0'
$ vendor/bin/behat --init
Quoi tester dans mon projet
Périmètre fonctionnel
● Une implémentation personnalisée des permissions (périmètres)
● Des données remontent dans un export (partenaires)
● Les contenus publiés dans une section sont accessibles en lecture et en
édition selon les périmètres d’un utilisateur (dashboard)
En tant qu’administrateur des périmètres, je veux pouvoir permettre
à un utilisateur de devenir contributeur ou chef de rédaction en le
rattachant à une section afin qu'il puisse ne modifier que les
contenus liés à cette section.
Fonctionnalité : Attribution des périmètres
Fonctionnalité : Attribution des périmètres
Critères d’acceptation :
● Un utilisateur n’a pas de périmètre assigné par défaut
● Un utilisateur ne peut pas créer de contenu dans une section s’il n’a pas les
droits pour ce périmètre
● Un utilisateur peut créer un contenu dans une section s’il possède le
périmètre associé
Exemple de scénario Behat
Fonctionnalité : Je teste mes périmètres
Scénario : Un nouvel utilisateur n'a pas de périmètre associé
[Given|Etant donné / Lorsque] je suis connecté en tant qu'utilisateur
possédant le role "Admin"
[When|Quand] je vais sur "/admin/people/create"
[Then|Alors] je devrais voir "Aucun Périmètre ajouté pour l'instant."
perimetres.feature
1 à n
Les drivers exposent des commandes
Mink + Drupal Extension donnent accès à une bibliothèque d’actions enrichie
$ bin/behat -di # Liste les actions disponibles
● Je visite la page <chemin>
● Je devrais voir le lien <lien>
● Je ne devrais pas voir le bouton
<bouton>
● Le code de réponse HTTP
devrait être <code>
● Je suis connecté comme utilisateur
avec le rôle <role>
● Je clique sur le lien <lien> de la ligne
<ligne>
● Je consulte un contenu de type
<type> dont le titre est <titre>
● Je sais la valeur <valeur> pour le
champ <champ>
$ ./behat perimetres.feature
Lancement d’un test behat
Binaire ^ ^ Fonctionnalité à tester
@api
Fonctionnalité: Attribution des périmètres
En tant qu'administrateur des permissions, je veux pouvoir permettre à un utilisateur de
devenir contributeur, chef de rédaction, le rattacher au marketing d'une section
particulière afin qu'il puisse ne modifier que les contenus liés à cette section.
Scénario: Un nouvel utilisateur n'a pas de périmètre associé
Etant donné je suis connecté en tant qu'utilisateur possédant le role "Admin"
Quand je vais sur "/admin/people/create"
Alors je devrais voir "Aucun Périmètre ajouté pour l'instant."
default:
suites:
default:
contexts:
- FeatureContext
- DrupalDrupalExtensionContextDrupalContext
- DrupalDrupalExtensionContextMinkContext
- DrupalDrupalExtensionContextMessageContext
- DrupalDrupalExtensionContextDrushContext
extensions:
BehatMinkExtension:
goutte: ~
selenium2: ~
base_url: http://artusamak.gazette.fr
DrupalDrupalExtension:
blackbox: ~
api_driver: drupal
text:
username_field: Nom d'utilisateur
password_field: Mot de passe
log_in: Se connecter
log_out: Se déconnecter
drupal:
drupal_root: "/var/www/gazette/web"
behat.config.yml
Lancement des tests dans l’IC
./vendor/bin/behat # Exécutable Behat
--lang=fr # Instructions en français
--config=./../behat/behat.localdev.yml # Fichier de conf de l'environnement
./../behat # Dossier des features à lancer
--format=progress # Format le résultat de façon condensée
● Lancer tous les tests à chaque build
Et un jour, le saint graal...
Il est possible d’ajouter ses propres commandes
● Une instruction est une chaîne de caractères passée dans une expression
régulière associée à une méthode d’une classe à laquelle on peut passer
des arguments.
« Je peux créer un dossier dans la section "La gazette Magazine" »
/**
* @Then je peux créer un dossier dans la section :section
* @Then l'utilisateur :name peut créer un dossier dans la section :section
*/
public function userCanCreateDossierInSection($section, $name = '');
public function userCanCreateDossierInSection($section, $name = '') {
// Connexion si l'utilisateur demandé n'est pas l'utilisateur courant.
if (!empty($name)) {
$user = $this->drupalContext->getUserManager()->getUser($name);
$this->drupalContext->login($user);
}
$this->drupalContext->getSession()->visit('/node/add/dossier');
$this->minkContext->assertResponseStatus(200);
// Chargement de la section pour obtenir son ID.
$section = $this->loadSectionFromName($section);
// Parcours des options disponibles pour le champ sections.
$selector = 'select[name="field_sections"] option';
$available_sections = $this->drupalContext->getSession()->getPage()->findAll('css', $selector);
foreach ($available_sections as $available_section) {
// On compare l'ID de la section car son nom peut être précédé d'un "-"
// s'il y a des termes parents dans la liste des sections.
if ($available_section->getValue() == $section->id()) {
return TRUE;
}
}
throw new Exception(sprintf("Droits insuffisants pour publier dans la section '%s'", $section->getName()));
}
Snippets pour accéder aux contextes
/**
* Gather any contexts needed.
*
* @BeforeScenario
*/
public function gatherContexts(BeforeScenarioScope $scope) {
$environment = $scope->getEnvironment();
$this->drupalContext = $environment->getContext('DrupalDrupalExtensionContextDrupalContext');
$this->minkContext = $environment->getContext('DrupalDrupalExtensionContextMinkContext');
}
-----
$this->minkContext->pressButton('Ajouter Périmètre');
$this->minkContext->getSession()->getPage()->findAll('css', 'select[name$="field_metiers"]');$sites =
Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree('sites', 0, 1);
Appliquer la même recette pour tous les critères
#language: fr
@api
Fonctionnalité: Attribution des périmètres
En tant qu'administrateur des permissions, je veux pouvoir permettre à un utilisateur de devenir
contributeur, chef de rédaction, le rattacher au marketing d'une section particulière afin qu'il
puisse ne modifier que les contenus liés à cette section.
Scénario: Un nouvel utilisateur n'a pas de périmètre associé
Etant donné je suis connecté en tant qu'utilisateur possédant le role "Admin"
Quand je vais sur "/admin/people/create"
Alors je devrais voir "Aucun Périmètre ajouté pour l'instant."
Scénario: Un utilisateur ne peut pas créer de dossier dans une autre section que celle pour
laquelle il a les droits
Etant donné un utilisateur nommé "behat"
Et je suis connecté en tant qu'utilisateur "behat"
Alors je ne peux pas créer un dossier dans la section "La gazette Magazine"
Et je ne peux pas créer un dossier dans la section "Chrono Sport"
Quand un administrateur m'assigne un périmètre dans le pôle "Pôle Actu" avec le rôle "Chargé
d'édition"
Alors je peux créer un dossier dans la section "La gazette Magazine"
Et je ne peux pas créer un dossier dans la section "Chrono Sport"
permissions.feature
Pour aller plus loin
Fonctionnalités Behat complémentaires
● « Backgrounds » si des actions préparatoires sont à effectuer avant de lancer
des scénarios (contexte partagé qui évite la répétition)
● Chaines multilignes avec une syntaxe particulière
● Tableaux de données
● Boucles avec les « scenario outlines »
Attention à certains points
● Mutualiser les actions
● Créer une librairie qui fait sens
● Driver VS API
DrupalDriverCoresDrupal8::nodeCreate() !== DrupalNodeEntityNode::create()
Poursuite et remerciements
● Votre meilleur allié : http://mink.behat.org/en/latest/index.html
● Travail en cours pour migrer tous les tests en PHPUnit
https://www.drupal.org/node/2735005
Relativement accessible pour des débutants
● PR de traduction FR https://github.com/jhedstrom/drupalextension/pull/374
● Inspiré de la présentation de Pieter Frensen (CE) présentation DDD Séville.

More Related Content

What's hot

GWT : under the hood
GWT : under the hoodGWT : under the hood
GWT : under the hood
svuillet
 
Ajax et Accessibilite
Ajax et AccessibiliteAjax et Accessibilite
Ajax et Accessibilite
mikeh
 
Une (simple) présentation de Apache Maven 2
Une (simple) présentation de Apache Maven 2Une (simple) présentation de Apache Maven 2
Une (simple) présentation de Apache Maven 2
teejug
 
Workshop Spring - Session 4 - Spring Batch
Workshop Spring -  Session 4 - Spring BatchWorkshop Spring -  Session 4 - Spring Batch
Workshop Spring - Session 4 - Spring Batch
Antoine Rey
 
Uni.sherbrooke 2015 créez la meilleur application grâce à gwt, gwtp et j...
Uni.sherbrooke 2015   créez la meilleur application grâce à gwt, gwtp et j...Uni.sherbrooke 2015   créez la meilleur application grâce à gwt, gwtp et j...
Uni.sherbrooke 2015 créez la meilleur application grâce à gwt, gwtp et j...
Arcbees
 

What's hot (20)

Django by mrjmad
Django by mrjmadDjango by mrjmad
Django by mrjmad
 
Drupal - La puissance de Drush
Drupal - La puissance de DrushDrupal - La puissance de Drush
Drupal - La puissance de Drush
 
20081113 - Nantes Jug - Apache Maven
20081113 - Nantes Jug - Apache Maven20081113 - Nantes Jug - Apache Maven
20081113 - Nantes Jug - Apache Maven
 
Partie 2: Angular
Partie 2: AngularPartie 2: Angular
Partie 2: Angular
 
20091020 - Normandy Jug - Builders Battle
20091020 - Normandy Jug - Builders Battle20091020 - Normandy Jug - Builders Battle
20091020 - Normandy Jug - Builders Battle
 
Presentation of GWT 2.4 (PDF version)
Presentation of GWT 2.4 (PDF version)Presentation of GWT 2.4 (PDF version)
Presentation of GWT 2.4 (PDF version)
 
Présentation1
Présentation1Présentation1
Présentation1
 
Une visite guidée d’Internet Explorer 9 et HTML5 pour les développeurs Web
Une visite guidée d’Internet Explorer 9 et HTML5 pour les développeurs WebUne visite guidée d’Internet Explorer 9 et HTML5 pour les développeurs Web
Une visite guidée d’Internet Explorer 9 et HTML5 pour les développeurs Web
 
Presentation of GWT 2.4 (PowerPoint version)
Presentation of GWT 2.4 (PowerPoint version)Presentation of GWT 2.4 (PowerPoint version)
Presentation of GWT 2.4 (PowerPoint version)
 
GWT : under the hood
GWT : under the hoodGWT : under the hood
GWT : under the hood
 
Chapter1
Chapter1Chapter1
Chapter1
 
Drupal7 - Bonnes Pratiques (Partie 1)
Drupal7 - Bonnes Pratiques (Partie 1)Drupal7 - Bonnes Pratiques (Partie 1)
Drupal7 - Bonnes Pratiques (Partie 1)
 
Ajax et Accessibilite
Ajax et AccessibiliteAjax et Accessibilite
Ajax et Accessibilite
 
Une (simple) présentation de Apache Maven 2
Une (simple) présentation de Apache Maven 2Une (simple) présentation de Apache Maven 2
Une (simple) présentation de Apache Maven 2
 
Workshop Spring - Session 4 - Spring Batch
Workshop Spring -  Session 4 - Spring BatchWorkshop Spring -  Session 4 - Spring Batch
Workshop Spring - Session 4 - Spring Batch
 
Apache Maven 3
Apache Maven 3Apache Maven 3
Apache Maven 3
 
HTML5
HTML5HTML5
HTML5
 
Symfony with angular.pptx
Symfony with angular.pptxSymfony with angular.pptx
Symfony with angular.pptx
 
Uni.sherbrooke 2015 créez la meilleur application grâce à gwt, gwtp et j...
Uni.sherbrooke 2015   créez la meilleur application grâce à gwt, gwtp et j...Uni.sherbrooke 2015   créez la meilleur application grâce à gwt, gwtp et j...
Uni.sherbrooke 2015 créez la meilleur application grâce à gwt, gwtp et j...
 
Introduction à React JS
Introduction à React JSIntroduction à React JS
Introduction à React JS
 

Similar to On test quoi - DCLannion 2017

Oxalide Morning tech #2 - démarche performance
Oxalide Morning tech #2 - démarche performanceOxalide Morning tech #2 - démarche performance
Oxalide Morning tech #2 - démarche performance
Ludovic Piot
 
Développement d’extensions WordPress
Développement d’extensions WordPressDéveloppement d’extensions WordPress
Développement d’extensions WordPress
Chi Nacim
 
Panels, une autre façon de construire. DrupalCamp Paris 2013
Panels, une autre façon de construire. DrupalCamp Paris 2013Panels, une autre façon de construire. DrupalCamp Paris 2013
Panels, une autre façon de construire. DrupalCamp Paris 2013
bellesmanieres
 

Similar to On test quoi - DCLannion 2017 (20)

Installation Et Configuration De Nutch
Installation Et Configuration De NutchInstallation Et Configuration De Nutch
Installation Et Configuration De Nutch
 
Outils front-end
Outils front-endOutils front-end
Outils front-end
 
Morning tech #2 - Démarche performance slides
Morning tech #2 - Démarche performance slidesMorning tech #2 - Démarche performance slides
Morning tech #2 - Démarche performance slides
 
Oxalide Morning tech #2 - démarche performance
Oxalide Morning tech #2 - démarche performanceOxalide Morning tech #2 - démarche performance
Oxalide Morning tech #2 - démarche performance
 
Spring Boot & Containers - Do's & Don'ts
Spring Boot & Containers - Do's & Don'tsSpring Boot & Containers - Do's & Don'ts
Spring Boot & Containers - Do's & Don'ts
 
Cours javascript
Cours javascriptCours javascript
Cours javascript
 
Meilleures pratiques pour construire un site web Drupal
Meilleures pratiques pour construire un site web DrupalMeilleures pratiques pour construire un site web Drupal
Meilleures pratiques pour construire un site web Drupal
 
Drupal en bibliothèque (2008)
Drupal en bibliothèque (2008)Drupal en bibliothèque (2008)
Drupal en bibliothèque (2008)
 
Meetup laravel
Meetup laravelMeetup laravel
Meetup laravel
 
Prise en main de Jhipster
Prise en main de JhipsterPrise en main de Jhipster
Prise en main de Jhipster
 
Comment récupérer un projet Web pourri ... et réussir à travailler dessus.
Comment récupérer un projet Web pourri ... et réussir à travailler dessus.Comment récupérer un projet Web pourri ... et réussir à travailler dessus.
Comment récupérer un projet Web pourri ... et réussir à travailler dessus.
 
Tout comprendre de Nuxeo Drive - Nuxeo Tour 2014 - workshop
Tout comprendre de Nuxeo Drive - Nuxeo Tour 2014 - workshopTout comprendre de Nuxeo Drive - Nuxeo Tour 2014 - workshop
Tout comprendre de Nuxeo Drive - Nuxeo Tour 2014 - workshop
 
Développement d’extensions WordPress
Développement d’extensions WordPressDéveloppement d’extensions WordPress
Développement d’extensions WordPress
 
Chaine de production pipeline
Chaine de production   pipelineChaine de production   pipeline
Chaine de production pipeline
 
Comment réussir son projet en Angular 1.5 ?
Comment réussir son projet en Angular 1.5 ?Comment réussir son projet en Angular 1.5 ?
Comment réussir son projet en Angular 1.5 ?
 
Aperçu de RequireJS
Aperçu de RequireJSAperçu de RequireJS
Aperçu de RequireJS
 
Django compressor
Django compressorDjango compressor
Django compressor
 
Drupal en bibliothèque (2009)
Drupal en bibliothèque (2009)Drupal en bibliothèque (2009)
Drupal en bibliothèque (2009)
 
Panels, une autre façon de construire. DrupalCamp Paris 2013
Panels, une autre façon de construire. DrupalCamp Paris 2013Panels, une autre façon de construire. DrupalCamp Paris 2013
Panels, une autre façon de construire. DrupalCamp Paris 2013
 
jQuery
jQueryjQuery
jQuery
 

More from Artusamak

Drupal comment contribuer
Drupal comment contribuerDrupal comment contribuer
Drupal comment contribuer
Artusamak
 

More from Artusamak (20)

Care for your backoffice - Drupal Dev Days Szeged 2014
Care for your backoffice - Drupal Dev Days Szeged 2014Care for your backoffice - Drupal Dev Days Szeged 2014
Care for your backoffice - Drupal Dev Days Szeged 2014
 
Agilité - Drupal et Scrum sont faits pour s'entendre
Agilité - Drupal et Scrum sont faits pour s'entendreAgilité - Drupal et Scrum sont faits pour s'entendre
Agilité - Drupal et Scrum sont faits pour s'entendre
 
Drupal 8: Mobile initiative - Drupalcamp Paris 2013
Drupal 8: Mobile initiative - Drupalcamp Paris 2013Drupal 8: Mobile initiative - Drupalcamp Paris 2013
Drupal 8: Mobile initiative - Drupalcamp Paris 2013
 
Il n'y a pas que Drupal dans la vie - Drupalcamp Paris 2013
Il n'y a pas que Drupal dans la vie - Drupalcamp Paris 2013Il n'y a pas que Drupal dans la vie - Drupalcamp Paris 2013
Il n'y a pas que Drupal dans la vie - Drupalcamp Paris 2013
 
Drupal un projet comme les autres ? Drupalcamp Paris 2013
Drupal un projet comme les autres ? Drupalcamp Paris 2013Drupal un projet comme les autres ? Drupalcamp Paris 2013
Drupal un projet comme les autres ? Drupalcamp Paris 2013
 
Openlayers - Drupalcamp Paris 2013
Openlayers - Drupalcamp Paris 2013Openlayers - Drupalcamp Paris 2013
Openlayers - Drupalcamp Paris 2013
 
Retour d'expérience : France Télévisions - Drupalcamp Paris 2013
Retour d'expérience : France Télévisions - Drupalcamp Paris 2013Retour d'expérience : France Télévisions - Drupalcamp Paris 2013
Retour d'expérience : France Télévisions - Drupalcamp Paris 2013
 
Drupal, scrum et l'agilité - Drupalcamp Paris 2013
Drupal, scrum et l'agilité - Drupalcamp Paris 2013Drupal, scrum et l'agilité - Drupalcamp Paris 2013
Drupal, scrum et l'agilité - Drupalcamp Paris 2013
 
Comment contribuer à Drupal
Comment contribuer à DrupalComment contribuer à Drupal
Comment contribuer à Drupal
 
Contribuer à drupal
Contribuer à drupalContribuer à drupal
Contribuer à drupal
 
Drupal comment contribuer
Drupal comment contribuerDrupal comment contribuer
Drupal comment contribuer
 
Drupal commerce - Drupalcamp Toulouse
Drupal commerce - Drupalcamp ToulouseDrupal commerce - Drupalcamp Toulouse
Drupal commerce - Drupalcamp Toulouse
 
Drupal commerce nuts and bolts seville
Drupal commerce nuts and bolts   sevilleDrupal commerce nuts and bolts   seville
Drupal commerce nuts and bolts seville
 
Drupalcamp Nantes - Présentation entités
Drupalcamp Nantes - Présentation entitésDrupalcamp Nantes - Présentation entités
Drupalcamp Nantes - Présentation entités
 
Drupalcamp Nantes - Présentation Drush
Drupalcamp Nantes - Présentation DrushDrupalcamp Nantes - Présentation Drush
Drupalcamp Nantes - Présentation Drush
 
Drupalcamp Nantes - Présentation GIT
Drupalcamp Nantes - Présentation GITDrupalcamp Nantes - Présentation GIT
Drupalcamp Nantes - Présentation GIT
 
Drupalcamp Nantes - Optimisations drupal
Drupalcamp Nantes - Optimisations drupalDrupalcamp Nantes - Optimisations drupal
Drupalcamp Nantes - Optimisations drupal
 
Drupalcamp Nantes - Open layers
Drupalcamp Nantes - Open layersDrupalcamp Nantes - Open layers
Drupalcamp Nantes - Open layers
 
Drupalcamp Nantes - Lost in translation
Drupalcamp Nantes - Lost in translationDrupalcamp Nantes - Lost in translation
Drupalcamp Nantes - Lost in translation
 
Drupalcamp Nantes - Open layers
Drupalcamp Nantes - Open layersDrupalcamp Nantes - Open layers
Drupalcamp Nantes - Open layers
 

On test quoi - DCLannion 2017

  • 1. Mais en vrai on test quoi ? Drupalcamp Lannion 2017 27/10/2017 Présentation sous licence CC 4.0 BY-SA-NC par Artusamak
  • 2. Le point de départ
  • 3. Je vais tout retester Sarah, chef de projet
  • 4.
  • 5. Et si on se concentrait sur la valeur ajoutée ?
  • 6. Un projet parfaitement adapté aux tests ● Une base de code enrichie depuis 3 / 4 mois ● Du contenu et des utilisateurs existants (site déjà en prod) ● Des fonctionnalités limitées ● 2 développeurs sur le projet
  • 8. Différents types de tests automatisables ● Tests unitaires ● Tests d’intégration ● Tests fonctionnels ● Tests de montée en charge ● Tests d’accessibilité ● Tests de régressions ● Tests de sécurité ● ...
  • 9. Tests unitaires ● PHPUnit / UnitTestCase ● Tests rapides et autonomes (pas d’initialisation de base de données, peuvent être lancés depuis PHPStorm ❤) ● Exemple : si je charge une permission depuis un YAML, j’ai bien un titre, une description. ● On s’appuie sur des Mockups pour simuler les données d’entrées afin d’augmenter les performances. ● Utile pour tester vos services ou vos classes utilitaires.
  • 10. Tests d’intégration ● PHPUnit / KernelTestBase ● Permet d’accéder aux fonctions d’API de Drupal ● Se lance à partir d’une base vide (sans contenu) en RAM (peuvent être initialisés à partir d’artefacts) ● Exemple : En chargeant la définition d’une propriété (base field) les méthodes isReadOnly(), isComputed(), isTranslatable() me renvoient bien les valeurs du schéma.
  • 11. Tests fonctionnels ● Dépréciées : WebTestBase & KernelTestBase ● BrowserTestBase ● Drupal entièrement installé depuis un profil d’installation ● Très lent mais facile à écrire ● Exemple : Une vue m’affiche seulement les contenus pour lesquels j’ai une permission ● A privilégier pour valider des comportements liés au rendu
  • 12. Tests fonctionnels ● JavascriptTestBase ● Basé sur Mink + PhantomJS ● Un vrai navigateur web à disposition ● Interactions type drag’n drop ● Sert pour tester le JS du site de prod ● Exemple : Génération du nom machine d’un champ
  • 13. Tests fonctionnels ● Behat ● Test des fonctionnalités utilisateurs en écrivant des scénarios ● S’écrit en langage naturel ● S’appuie sur une bibliothèque d’instructions ● Pas fait pour tester du code ● Décrit des comportements attendus
  • 14.
  • 15. Mise en place de behat
  • 16. Outillage Behat 3 + Drupal extension https://www.drupal.org/project/drupalextension https://github.com/jhedstrom/drupalextension https://github.com/jhedstrom/DrupalDriver $ composer require drupal/drupal-extension='~3.0' $ vendor/bin/behat --init
  • 17. Quoi tester dans mon projet
  • 18. Périmètre fonctionnel ● Une implémentation personnalisée des permissions (périmètres) ● Des données remontent dans un export (partenaires) ● Les contenus publiés dans une section sont accessibles en lecture et en édition selon les périmètres d’un utilisateur (dashboard)
  • 19. En tant qu’administrateur des périmètres, je veux pouvoir permettre à un utilisateur de devenir contributeur ou chef de rédaction en le rattachant à une section afin qu'il puisse ne modifier que les contenus liés à cette section. Fonctionnalité : Attribution des périmètres
  • 20. Fonctionnalité : Attribution des périmètres Critères d’acceptation : ● Un utilisateur n’a pas de périmètre assigné par défaut ● Un utilisateur ne peut pas créer de contenu dans une section s’il n’a pas les droits pour ce périmètre ● Un utilisateur peut créer un contenu dans une section s’il possède le périmètre associé
  • 21. Exemple de scénario Behat Fonctionnalité : Je teste mes périmètres Scénario : Un nouvel utilisateur n'a pas de périmètre associé [Given|Etant donné / Lorsque] je suis connecté en tant qu'utilisateur possédant le role "Admin" [When|Quand] je vais sur "/admin/people/create" [Then|Alors] je devrais voir "Aucun Périmètre ajouté pour l'instant." perimetres.feature 1 à n
  • 22. Les drivers exposent des commandes Mink + Drupal Extension donnent accès à une bibliothèque d’actions enrichie $ bin/behat -di # Liste les actions disponibles ● Je visite la page <chemin> ● Je devrais voir le lien <lien> ● Je ne devrais pas voir le bouton <bouton> ● Le code de réponse HTTP devrait être <code> ● Je suis connecté comme utilisateur avec le rôle <role> ● Je clique sur le lien <lien> de la ligne <ligne> ● Je consulte un contenu de type <type> dont le titre est <titre> ● Je sais la valeur <valeur> pour le champ <champ>
  • 23. $ ./behat perimetres.feature Lancement d’un test behat Binaire ^ ^ Fonctionnalité à tester @api Fonctionnalité: Attribution des périmètres En tant qu'administrateur des permissions, je veux pouvoir permettre à un utilisateur de devenir contributeur, chef de rédaction, le rattacher au marketing d'une section particulière afin qu'il puisse ne modifier que les contenus liés à cette section. Scénario: Un nouvel utilisateur n'a pas de périmètre associé Etant donné je suis connecté en tant qu'utilisateur possédant le role "Admin" Quand je vais sur "/admin/people/create" Alors je devrais voir "Aucun Périmètre ajouté pour l'instant."
  • 24. default: suites: default: contexts: - FeatureContext - DrupalDrupalExtensionContextDrupalContext - DrupalDrupalExtensionContextMinkContext - DrupalDrupalExtensionContextMessageContext - DrupalDrupalExtensionContextDrushContext extensions: BehatMinkExtension: goutte: ~ selenium2: ~ base_url: http://artusamak.gazette.fr DrupalDrupalExtension: blackbox: ~ api_driver: drupal text: username_field: Nom d'utilisateur password_field: Mot de passe log_in: Se connecter log_out: Se déconnecter drupal: drupal_root: "/var/www/gazette/web" behat.config.yml
  • 25. Lancement des tests dans l’IC ./vendor/bin/behat # Exécutable Behat --lang=fr # Instructions en français --config=./../behat/behat.localdev.yml # Fichier de conf de l'environnement ./../behat # Dossier des features à lancer --format=progress # Format le résultat de façon condensée ● Lancer tous les tests à chaque build
  • 26. Et un jour, le saint graal...
  • 27.
  • 28. Il est possible d’ajouter ses propres commandes ● Une instruction est une chaîne de caractères passée dans une expression régulière associée à une méthode d’une classe à laquelle on peut passer des arguments. « Je peux créer un dossier dans la section "La gazette Magazine" » /** * @Then je peux créer un dossier dans la section :section * @Then l'utilisateur :name peut créer un dossier dans la section :section */ public function userCanCreateDossierInSection($section, $name = '');
  • 29. public function userCanCreateDossierInSection($section, $name = '') { // Connexion si l'utilisateur demandé n'est pas l'utilisateur courant. if (!empty($name)) { $user = $this->drupalContext->getUserManager()->getUser($name); $this->drupalContext->login($user); } $this->drupalContext->getSession()->visit('/node/add/dossier'); $this->minkContext->assertResponseStatus(200); // Chargement de la section pour obtenir son ID. $section = $this->loadSectionFromName($section); // Parcours des options disponibles pour le champ sections. $selector = 'select[name="field_sections"] option'; $available_sections = $this->drupalContext->getSession()->getPage()->findAll('css', $selector); foreach ($available_sections as $available_section) { // On compare l'ID de la section car son nom peut être précédé d'un "-" // s'il y a des termes parents dans la liste des sections. if ($available_section->getValue() == $section->id()) { return TRUE; } } throw new Exception(sprintf("Droits insuffisants pour publier dans la section '%s'", $section->getName())); }
  • 30.
  • 31. Snippets pour accéder aux contextes /** * Gather any contexts needed. * * @BeforeScenario */ public function gatherContexts(BeforeScenarioScope $scope) { $environment = $scope->getEnvironment(); $this->drupalContext = $environment->getContext('DrupalDrupalExtensionContextDrupalContext'); $this->minkContext = $environment->getContext('DrupalDrupalExtensionContextMinkContext'); } ----- $this->minkContext->pressButton('Ajouter Périmètre'); $this->minkContext->getSession()->getPage()->findAll('css', 'select[name$="field_metiers"]');$sites = Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree('sites', 0, 1);
  • 32. Appliquer la même recette pour tous les critères
  • 33. #language: fr @api Fonctionnalité: Attribution des périmètres En tant qu'administrateur des permissions, je veux pouvoir permettre à un utilisateur de devenir contributeur, chef de rédaction, le rattacher au marketing d'une section particulière afin qu'il puisse ne modifier que les contenus liés à cette section. Scénario: Un nouvel utilisateur n'a pas de périmètre associé Etant donné je suis connecté en tant qu'utilisateur possédant le role "Admin" Quand je vais sur "/admin/people/create" Alors je devrais voir "Aucun Périmètre ajouté pour l'instant." Scénario: Un utilisateur ne peut pas créer de dossier dans une autre section que celle pour laquelle il a les droits Etant donné un utilisateur nommé "behat" Et je suis connecté en tant qu'utilisateur "behat" Alors je ne peux pas créer un dossier dans la section "La gazette Magazine" Et je ne peux pas créer un dossier dans la section "Chrono Sport" Quand un administrateur m'assigne un périmètre dans le pôle "Pôle Actu" avec le rôle "Chargé d'édition" Alors je peux créer un dossier dans la section "La gazette Magazine" Et je ne peux pas créer un dossier dans la section "Chrono Sport" permissions.feature
  • 34.
  • 36. Fonctionnalités Behat complémentaires ● « Backgrounds » si des actions préparatoires sont à effectuer avant de lancer des scénarios (contexte partagé qui évite la répétition) ● Chaines multilignes avec une syntaxe particulière ● Tableaux de données ● Boucles avec les « scenario outlines »
  • 37. Attention à certains points ● Mutualiser les actions ● Créer une librairie qui fait sens ● Driver VS API DrupalDriverCoresDrupal8::nodeCreate() !== DrupalNodeEntityNode::create()
  • 38. Poursuite et remerciements ● Votre meilleur allié : http://mink.behat.org/en/latest/index.html ● Travail en cours pour migrer tous les tests en PHPUnit https://www.drupal.org/node/2735005 Relativement accessible pour des débutants ● PR de traduction FR https://github.com/jhedstrom/drupalextension/pull/374 ● Inspiré de la présentation de Pieter Frensen (CE) présentation DDD Séville.