Giant druplicon. The pupils in it's eyes are made of Codeception's icons

Comment nous avons fait ami avec Codeception et Drupal

Nous faisons beaucoup de développement Drupal. Nous effectuons également de nombreux tests automatisés. C'est pourquoi nous avons décidé de compléter la fonctionnalité standard de Codeception avec de nouveaux modules dédiés à Drupal. Cela nous aide beaucoup dans notre travail quotidien.

Comme dans notre article précédent, tous les exemples énumérés ci-dessous seront basés sur un projet basé sur docker-console, c'est pourquoi nous encourageons tout le monde à lire d'abord les articles précédents si vous ne l'avez pas encore fait. Si vous avez déjà votre projet Codeception et que vous souhaitez simplement le modifier légèrement pour qu'il fonctionne mieux avec Drupal, cet article est également pour vous.
Lorsque nous avons essayé pour la première fois d'élargir la fonctionnalité de nos tests, nous avions des exigences que les modules existants ne remplissaient pas, c'est pourquoi la plupart des solutions listées ci-dessous ont été créées par nous. Elles sont toutes basées sur d'autres solutions précédemment disponibles, mais nous espérons que vous apprécierez la manière dont Droptica les a développées et les a rendues un ensemble cohérent, disponible en un clin d'œil dans la configuration de votre projet Codeception.

codeception-drupal-bootstrap

Le premier module présenté dans cet article est codeception-drupal-bootstrap, que vous pouvez trouver à https://github.com/droptica/codeception-drupal-bootstrap
Ceci est un fork d'un module : https://github.com/Chapabu/codeception-module-drupal (Il a été modifié par nous, car à l'origine, il n'était pas possible de l'utiliser dans plusieurs suites en même temps, et de plus, il n'y avait pas de version pour Drupal 8). Il permet d'utiliser les fonctions de Drupal dans les tests et d'autres modules de Codeception

Configuration

Pour pouvoir utiliser ce module, vous devez le configurer dans un fichier yaml pour une suite donnée, par exemple unit.suite.yml.
Activation dans la configuration de la suite de tests pour Drupal 7.
 

- \Codeception\Module\Drupal7\Drupal7:
            root: '/app/app'
            relative: no


Déblocage de la configuration pour Drupal 8 :
   

- \Codeception\Module\Drupal8\Drupal8:
            root: '/app/app/'
            env: 'prod'
            relative: no
            site_dir: 'default'

 
Exemple

Son utilisation est évidente pour quiconque travaille avec Drupal. Dans un article récent, nous vous avons montré un exemple de vérification si un module donné est activé en utilisant les commandes Drupal. Dans ce billet de blog, nous allons vous montrer un autre test utile pour vérifier si les fonctionnalités de votre site Web ne sont pas remplacées. Si vous voulez que cet exemple fonctionne avec notre projet, vous devez ajouter le module de fonctionnalités à votre projet et exporter certaines fonctionnalités. Vous pouvez également récupérer les fichiers de la branche codeception-drupal, où nous l'avons déjà fait pour vous.

<?php

class ExampleUnitTest extends \Codeception\Test\Unit
{
    /**
     * @var \UnitTester
     */
    protected $tester;

    protected function _before()
    {
    }

    protected function _after()
    {
    }

    /**   TESTS     */
     
    public function testFeaturesDefault() {

      module_load_include('inc', 'features', 'features.export');

      // Charger les informations sur la fonctionnalité.
      $features[] = 'test';
      $features_states = features_get_component_states($features, FALSE, TRUE);

      foreach ($features_states as $feature_name => $feature_state) {
        $overridden_features = array_filter($feature_state, function($item) {
          return $item != FEATURES_DEFAULT;
        });
        $this->assertEquals(TRUE, empty($overridden_features), 'Feature ' . $feature_name . ' is overridden.');
      }
    }

}


codeception-drupal-users

Un autre module présenté dans cet article est codeception-drupal-users, que vous pouvez trouver à https://github.com/droptica/codeception-drupal-users . Ceci est un module drupal-user-registry modifié – https://github.com/ixis/codeception-module-drupal-user-registry , utilisé pour la création automatique d'utilisateurs de test lors du temps d'exécution de la suite de tests. En utilisant le module, vous pouvez rapidement créer et utiliser des utilisateurs de test avec des rôles spécifiés lors de vos tests. Par défaut, tous les utilisateurs de test seront supprimés après avoir terminé tous les tests d'une suite donnée (à moins d'avoir configuré autrement). 

Le module original utilise drush pour créer des utilisateurs. Avec cette méthode, il n'était pas possible de remplir des champs de profil personnalisés, donc au lieu de drush, notre module utilise les fonctions de Drupal pour cela. Grâce à cela, il est possible de remplir à la fois les détails utilisateur standard et aussi les champs de profil personnalisés.

Configuration

La configuration est simple et se fait entièrement dans un fichier de configuration d'une suite donnée. Cependant, il est nécessaire de se rappeler de plusieurs choses. Tout d'abord, pour que ce module fonctionne, vous devez activer le module codeception-drupal-bootstrap dans une suite donnée. De plus, le module Entity API (https://www.drupal.org/project/entity) doit également être activé dans le projet.

Exemples

Il est toujours préférable de discuter de la configuration à l'aide d'un exemple, c'est pourquoi nous avons ajouté deux champs supplémentaires et trois nouveaux rôles pour les utilisateurs. (Si vous ne savez pas comment faire cela dans votre projet, vous pouvez récupérer les modifications de la branche docker-drupal). Après avoir activé le module, nous devons spécifier quels types d'utilisateurs nous voulons créer. Pour ce faire, nous devons d'abord déclarer les rôles de nos utilisateurs (vous pouvez le faire comme dans l'exemple présenté ci-dessous ou déclarer, par exemple, des rôles personnalisés, où l'utilisateur aura plusieurs rôles définis dans le système). Après avoir décrit les rôles dans le projet, je spécifie également les données qui seront utilisées pour remplir nos nouveaux champs (je pourrais les spécifier pour chaque utilisateur séparément). Après cela, nous pouvons passer à la spécification des utilisateurs exacts que nous voulons que codeception crée avant d'exécuter nos tests. À la fin, nous devrions avoir une valeur "true" dans "create" si nous voulons que nos utilisateurs soient créés avant d'exécuter une suite donnée. Il en va de même pour "delete" – cela supprime nos utilisateurs après avoir exécuté une suite de tests. Dans mon cas, les utilisateurs ne sont pas supprimés afin de pouvoir vérifier dans le système s'ils ont vraiment été créés. Si nous exécutons le test deux fois, les nouveaux utilisateurs ne seront pas dupliqués, nous recevrons un message d'erreur indiquant que l'utilisateur existe déjà dans le système.

- ManageUsers:
            defaultPass: "123"

#Rôles disponibles:
#1 utilisateur anonyme
#2 utilisateur authentifié
#3 administrateur
#4 éditeur
#5 utilisateur
#6 personne

            roles_admin: &roles_admin
              2: "utilisateur authentifié"
              3: administrateur

            roles_editor: &roles_editor
              2: "utilisateur authentifié"
              4: éditeur

            roles_user: &roles_user
              2: "utilisateur authentifié"
              5: utilisateur

            roles_nodoby: &roles_nodoby
              2: "utilisateur authentifié"
              6: personne

            custom_fields: &custom_fields
              field_inne_pole: 'Fname'
              field_custom_field: 'key1'

            users:
              admin_user:
                name: admin_user
                email: [email protected]
                roles: *roles_admin
                custom_fields:
                  <<: *custom_fields

              editor_user:
                name: editor_user
                email: [email protected]
                roles: *roles_editor
                custom_fields:
                  field_inne_pole: 'Fname2'
                  field_custom_field: 'key2'

              user_user:
                name: user_user
                email: [email protected]
                roles: *roles_user
                custom_fields:
                  <<: *custom_fields

              nodoby_user:
                name: nodoby_user
                email: [email protected]
                roles: *roles_nodoby
                custom_fields:
                  <<: *custom_fields

            create: true                 # Si l'on doit créer tous les utilisateurs de test définis au début de la suite.
            delete: false                 # Si l'on doit supprimer tous les utilisateurs de test définis à la fin de la suite.


Pour Drupal 8, la configuration du module est presque identique. La seule différence est l'activation du module dans la configuration en utilisant :

- \Codeception\Module\Drupal8\ManageUsers:


au lieu de ManageUsers.
Bien sûr, vous pouvez utiliser les fonctions de ce module lors de l'écriture des cas de test. Parmi les plus utiles, il y a celles qui nous permettent de nous référer à un utilisateur de test ou à un groupe d'utilisateurs :

  • getAllTestUsers()
  • getTestUsersByRoles($roles = array(), $return_one_user = FALSE)
  • getTestUserByName($username)

codeception-drupal-content-types 


Un autre de nos modules Drupal est codeception-drupal-content-types, que vous pouvez trouver à : https://github.com/droptica/codeception-drupal-content-types . Il a été basé sur : https://github.com/ixis/codeception-drupal-content-types et est utilisé pour créer et supprimer des nœuds de test. 


Configuration


Pour activer : 

 - DrupalContentTypeRegistry:
            contentTypesAutoDump: true
            contentTypesAutoDumpFile: "contentTypes.yml"
            contentTypesFile: "contentTypes.yml"
            customFieldsFile: "contentTypesOverrides.yml"


Après cela, l'exécution des tests devrait générer un fichier contentTypes.yml, listant la structure des nœuds disponibles dans le projet. Un exemple d'un tel fichier peut être vu dans l'image ci-dessous.

Structure of nodes

Si l'un des types de contenu a des champs définis comme la collection de champs ou d'autres, qui comprennent des champs imbriqués (par exemple, le lieu), le fichier contentTypes.yml inclura uniquement les principaux champs, sans ceux imbriqués. Pour remplir les champs imbriqués, comme dans la collection de champs, vous devez les inclure dans le fichier contentTypesOverrides.yml. Toutes les personnes qui ont initié le projet en utilisant docker-console unit-tests ou qui ont fusionné le code de notre dépôt d'exemple devraient déjà avoir ce fichier dans leurs projets. Il devrait contenir des indications sur la façon de remplacer la configuration donnée et ressembler à celui ci-dessous.

Suggestion of tests in representative repository

Exemple

Dans notre exemple, nous allons vous montrer comment créer un nœud de type article en utilisant ce module.

class NewNodeTestCest
{

 /**
   * @var string
   * article_title
   */
  private $article_title;

  /**
   * @var string
   * article_body
   */
  private $article_body;

  /**
   * @var string
   * article_tags
   */
  private $article_tags;

  function __construct() {
    $this->article_title = 'Test article';
    $this->article_body = 'Test article body';
    $this->article_tags = 'Test article tag'; 
  }

  public function _before(AcceptanceTester $I) {
  }

  public function _after(AcceptanceTester $I) {
  }

  /**   TESTS     */

  /**
   * @param \AcceptanceTester $I
   * 
   */
  public function newArticle(AcceptanceTester $I, UserSteps $U) {
    $I->wantTo('Test - I can log in as admin and add and delete article');
    $I->amOnPage('/');
    $user = $I->getTestUserByName('admin_user');
    $U->login($user->name, $user->pass);
     $fields_values = array(
      'title' => $this->article_title,
      'body' => $this->article_body,
      'field_tags' => $this->article_tags
    );
    $I->createNode($I, 'article', $fields_values, NULL, FALSE);
    $nid = $I->grabLastCreatedNid($I);
    $I->deleteNodeFromStorage($nid);
    $I->amOnPage('/user/logout');
  }

 }


codeception-drupal-content-types + NodeSteps

Pour rendre notre travail avec le module encore plus facile, nous avons ajouté quelques fonctions de support supplémentaires, qui nous permettent de spécifier quel utilisateur nous voulons utiliser pour ajouter ou supprimer un nœud donné. Le fichier NodeSteps contient des fonctions qui nous connectent en tant qu'utilisateur donné avant d'ajouter/retirer un nœud. Un exemple de l'utilisation de ces fonctions peut être trouvé ci-dessous, ici nous ajoutons un nœud "page" en tant que admin_user.

<?php

use Step\Acceptance\UserSteps;
use Step\Acceptance\NodeSteps;

class NewNodeAsUserTestCest
{

 /**
   * @var string
   * page_title
   */
  private $page_title;

  /**
   * @var string
   * page_body
   */
  private $page_body;

  function __construct() {
    $this->page_title = 'Test page';
    $this->page_body = 'Test page body';
  }

  public function _before(AcceptanceTester $I) {
  }

  public function _after(AcceptanceTester $I) {
  }

  /**   TESTS     */

  /**
   * @param \AcceptanceTester $I
   * 
   */
  public function newPage(AcceptanceTester $I, UserSteps $U, NodeSteps $N) {
    $I->wantTo('Test - I can add and delete page as admin');
    $I->amOnPage('/');
     $fields_values = array(
      'title' => $this->page_title,
      'body' => $this->page_body
    );
    $nid = $N->createNewNodeAsUser('admin_user', 'article', $fields_values);
    $N->deleteNodeAsUser('admin_user', $nid);
  }

 }

codeception-drupal-storage

Le dernier module présenté dans l'article d'aujourd'hui est codeception-drupal-storage, que vous pouvez trouver à : https://github.com/droptica/codeception-drupal-storage
Il est utilisé pour stocker les variables et les nœuds de test que nous créons globalement dans toute la suite de tests jusqu'à ce que nous finissions d'exécuter les tests d'une suite donnée.
Dans ce module, vous pouvez tirer parti des méthodes suivantes :

  • setVariableToStorage($name, $value)
  • getVariablesFromStorage($names = array())
  • getVariableFromStorage($name)
  • deleteVariableFromStorage($name)
  • appendNodeToStorage($nid)
  • getAllNodesFromStorage()
  • getNodeFromStorage($nid)
  • deleteNodeFromStorage($nid)


Configuration

Le module ne nécessite aucune configuration compliquée, il suffit de l'activer en ajoutant la ligne suivante dans le fichier de configuration d'une suite donnée.

- SuiteVariablesStorage


Exemple

Comme dans chaque cas, il est toujours préférable de voir ce que le module peut faire avec un exemple. Dans notre exemple, présenté ci-dessous, nous avons divisé la création d'un nœud, la vérification s'il a un contenu approprié et sa suppression en trois tests distincts, ce qui nous a permis de montrer comment nous sommes capables de déplacer une valeur donnée d'un test à un autre. Bien sûr, les tests ne doivent pas être dans un seul fichier ; cependant, il est vital qu'ils appartiennent tous à une seule suite car après l'exécution de la suite, toutes les valeurs créées pendant les tests sont supprimées. (De plus, vous pouvez retirer une valeur donnée à tout moment en utilisant la méthode appropriée.)

<?php

use Step\Acceptance\UserSteps;
use Step\Acceptance\NodeSteps;

class VariablesStorageTestCest
{

 /**
   * @var string
   * page_title
   */
  private $page_title;

  /**
   * @var string
   * page_body
   */
  private $page_body;

  function __construct() {
    $this->page_title = 'Test page';
    $this->page_body = 'Test page body';
  }

  public function _before(AcceptanceTester $I) {
  }

  public function _after(AcceptanceTester $I) {
  }

  /**   TESTS     */

  /**
   * @param \AcceptanceTester $I
   * 
   */
  public function newPage(AcceptanceTester $I, UserSteps $U, NodeSteps $N) {
    $I->wantTo('Test - I can log in as admin and add article');
    $I->amOnPage('/');
     $fields_values = array(
      'title' => $this->page_title,
      'body' => $this->page_body
    );
    $nid = $N->createNewNodeAsUser('admin_user', 'article', $fields_values);
    $I->setVariableToStorage('page_nid', $nid);
  }

  /**
   * @param \AcceptanceTester $I
   * 
   */
  public function seeTextOnPage(AcceptanceTester $I) {
    $I->wantTo('Test - I can see page title and body text on test page');
    $nid = $I-> getVariableFromStorage('page_nid');
    $I->amOnPage('/node/'.$nid);
    $I->canSee($this->page_title);
    $I->canSee($this->page_body);
  }

  /**
   * @param \AcceptanceTester $I
   * 
   */
  public function deletePage(AcceptanceTester $I, UserSteps $U, NodeSteps $N) {
    $I->wantTo('Test - I can delete test page');
    $nid = $I-> getVariableFromStorage('page_nid');
    $N->deleteNodeAsUser('admin_user', $nid);
  }

 }


Fichiers du projet

Vous pouvez exécuter les exemples décrits dans cet article en les téléchargeant depuis le dépôt du projet et en changeant de branche vers codeception-drupal.
Dépôt du projet:

https://github.com/DropticaExamples/docker-console-project-example

Dump de la base de données:

https://www.dropbox.com/s/r0o3u9gjp3dccd4/database.sql.tar.gz?dl=0

Fichiers du projet:

https://www.dropbox.com/s/hl506wciwj60fds/files.tar.gz?dl=0

 

Fonctions d'aide :

En plus d'ajouter des modules, nous ajouterons des fonctions spéciales à chaque projet, permettant de mieux tester le site. Nous avons déjà démontré ces fonctions lorsque nous avons présenté NodeSteps avec le module codeception-drupal-content-types. (Ce sont des classes spéciales, vous pouvez en lire plus à ce sujet ici : http://codeception.com/docs/06-ReusingTestCode#StepObjects

Nous les discuterons également en détail dans l'un de nos prochains articles.) Vous pouvez également écrire des fonctions d'aide dans des fichiers ajoutés à chaque suite de tests, par exemple, le fichier "Acceptance" dans _support/Helper ou créer un nouveau fichier et écrire des fonctions d'aide là-bas, comme dans notre exemple avec le fichier DrupalHelper trouvé dans le même dossier. Quel que soit le variant que vous choisissez, vous devez vous rappeler de débloquer l'accès à ces fonctions dans une suite donnée dans un fichier yaml, comme dans l'exemple ci-dessous.

Suite file. Arrow shows line "\Helper\Acceptance" listed under Enabled modules

Si vous ne le faites pas, vous devrez l'importer dans chaque fichier où vous voudrez utiliser une fonction donnée en ajoutant par exemple

use Step\Acceptance\UserSteps;
use Step\Acceptance\NodeSteps;


Conclusion

Nous espérons que vous apprécierez nos petites améliorations pour Drupal. Si vous utilisez une solution dédiée à Drupal et sur laquelle nous n'avons pas encore écrit, faites-le nous savoir – nous serons heureux d'élargir notre configuration avec de nouveaux modules intéressants. Si vous commencez votre aventure avec Codeception, nous vous encourageons à expérimenter et à écrire autant de tests que possible par vous-même, car comme vous le savez probablement déjà, "c'est en forgeant qu'on devient forgeron". De plus, nous invitons tout le monde à continuer de visiter notre blog – vous pouvez être sûr que nous écrirons plus sur cet outil à l'avenir.
 

3. Best practices for software development teams