Skip to main content

Integración Behat en Drupal: pasos a seguir para ejecutar nuestros primeros test

Como requisitos necesitaremos tener instalado Drupal y Behat con las extensiones necesarias para la integración con Drupal.

Prerequisitos

  • Instalación de Drupal
  • php 5.3.5 o más
  • Java (necesario para Selenium)
  • Selenium Server

Para más información visitar la pagina oficial: Drupal Extension to Behat and Mink

Instalación drupalextension (Behat + dependencias)

Para instalar Behat y las extensiones necesarias, nos basaremos en instalarlo mediante composer.

Instalación de Behat integrado directamente con Drupal a través de drupalextensión.

# create folder for drush for example opt:
mkdir /opt/behat && cd /opt/behat
# require drupal-extension
composer require drupal/drupal-extension
# Symlink to /usr/bin
ln -s /opt/behat/vendor/bin/behat /usr/local/bin/behat
# check version:
behat --version

Básicamente descargaremos drupal-extension más las dependencias necesarias, para ver más en concreto que dependencias se instala podremos ver todas desde este URL

https://packagist.org/packages/drupal/drupal-extension

 

Existen varios métodos de instalación tenemos más información en la documentación oficial que nos proporciona Behat.

http://docs.behat.org/en/stable/quick_start.html

Estructura base

Representaremos la estructura que tendrá al terminar el artículo, no es necesario saber exactamente cada elemento, solo la tendremos para identificar de manera más fácil la .

Este será el aspecto que tendrá al finalizar este artículo nuestro directorio dentro de un Drupal. De momento no entraremos en detalle de cada elemento, pero está estructura, nos servirá para visualizar todos los archivos que iremos generando a lo largo del artículo.

 

Drupal
├─sites
│  ├─all
│  │   └─test
│  │      └─behat
│  │         └─features
│  │             ├─*.feature
│  │             └─bootstrap
│  │                 └─FeatureContext.php
│  └─default
│    └─default.behat.yml

 

Primeros pasos

Una vez tengamos lo requisitos previos, esto quiere decir que partimos de tener instalado un Drupal y Behat como sus dependencias.

Empezaremos yendo al directorio donde esta instalado nuestro Drupal, una vez aquí generaremos la primero la estructura base.

# Vamos al directorio sites/all
cd sites/all
# Generamos una carpeta llamada test
mkdir test
# Generamos una carpeta llamada behat dentro de test
mkdir test/behat
# Vamos a test/behat
cd test/behat

behat_dir_basic.png

 

Una vez estamos dentro de este directorio ejecutaremos el siguiente comando de Behat.

 

behat --init

 

Después de ejecutar este comando Behat  generará la siguiente estructura de archivos.

 

behat_init_dir.png

behat_init.png

Un directorio llamado features,  dentro nuestro proyecto.
Este directorio contendrá tanto los archivos .features, con nuestros pasos, como una subcarpeta llamada bootstrap el cual contendrá todos los contextos que integremos y un archivo base donde podremos extender nuestras funcionalidades, hacer pasos custom, ... 

Contexto base generada

<?php                                                             
                                                                  
use Behat\Behat\Context\Context;                                  
use Behat\Behat\Context\SnippetAcceptingContext;                  
use Behat\Gherkin\Node\PyStringNode;                              
use Behat\Gherkin\Node\TableNode;                                 
                                                                  
/**                                                               
 * Defines application features from the specific context.        
 */                                                               
class FeatureContext implements Context, SnippetAcceptingContext  
{                                                                 
    /**                                                           
     * Initializes context.                                       
     *
     * Every scenario gets its own context instance.
     * You can also pass arbitrary arguments to the
     * context constructor through behat.yml.
     */
    public function __construct()
    {
    }
}

 

Llegados a este punto ya podremos ejecutar Behat y comprobar que lo tenemos instalado todo lo necesario.

# Ejecutamos behat para comprobar que funciona
behat

behat_start.png

 

Como vemos Behat se ejecuta pero no encuentra ningún Step o paso que ejecutar, vamos a generar nuestro primer archivo .feature.

Crearemos un archivo llamado anonymous.homepage.feature, está nomenclatura esta basada en BDD (Desarrollo guiado por comportamiento), es una buena practica y nos basaremos en ella, no entraremos en detalle pero es una buena practica a seguir.

Feature: Como usuario anónimo puedo acceder a la homepage
  
  Scenario: Anónimo navega a la homepage
    When I should see "Drupal"

Si volvemos a ejecutar ahora Behat de nuevo está vez si parará por el primer Step que hemos definido

Feature: Como usuario anónimo puedo acceder a la homepage
  Scenario: Anónimo navega a la homepage # features/anonymous.homepage.feature:3
    Given I go to "/"
1 scenario (1 undefined)
1 step (1 undefined)
0m0.01s (7.05Mb)
--- FeatureContext has missing steps. Define them with these snippets:
    /**
     * @Given I go to :arg1
     */
    public function iGoTo($arg1)
    {
        throw new PendingException();
    }

Como muestra está respuesta esta ejecutando el primero paso que hemos agregado a nuestro fichero.
Pero aquí nos surge un duda, como le digo a Behat la URL donde esta montado, que pasos ejecuta, Behat no me proporciona pasos ya definidos, ...

Todas estás dudas son solventadas con un archivo, nuestro archivo YAML o .yml que tendrá toda la configuración pertinente.

Este es el archivo base .yml, en el llamaremos a los contextos más utilizados y que se nos descargó drupalextension 

default:
  suites:
    default:
      contexts:
        - FeatureContext
        - Drupal\DrupalExtension\Context\DrupalContext
        - Drupal\DrupalExtension\Context\MinkContext
        - Drupal\DrupalExtension\Context\MessageContext
        - Drupal\DrupalExtension\Context\DrushContext
  extensions:
    Behat\MinkExtension:
      goutte: ~
      selenium2: ~
      base_url: http://seven.l
    Drupal\DrupalExtension:
      blackbox: ~

No vamos a entrar en detalle ya que para definir todos los aspectos configurables por cada contexto añadido, ... No podría llevar mucho tiempo solo definiremos los más importantes y agregaremos un par de archivos y como generar un archivo YAML que nos proporciona Behat 

 

Behat nos proporciona una manera de generar un archivo genérico

# Move to sites/default into the project
cd sites/default
# Create default.behat.yml 
behat --config-reference > default.behat.yml

Este seria el archivo default.behat.yml generado

testwork:
    argument:             []
    autoload:
        # Default:
        :                    %paths.base%/features/bootstrap
    suites:
        # Prototype
        name:
            # Enables/disables suite
            enabled:              true
            # Specifies suite type
            type:                 null
            # Specifies suite extra settings
            settings:
                # Prototype
                name:                 ~
    formatters:
        # Prototype
        name:
            # Prototype
            name:                 ~
    exceptions:
        # Output verbosity
        verbosity:            1 # Example: 1, 2, 3, 4
    gherkin:
        # Sets the gherkin parser cache folder
        cache:                /tmp/behat_gherkin_cache
        # Sets the gherkin filters (overridable by CLI options)
        filters:
            # Prototype
            name:                 ~
    calls:
        # Call executor will catch exceptions matching this level
        error_reporting:      32767
    translation:
        # Sets output locale for the tester
        locale:               en
        # Sets fallback output locale for the tester
        fallback_locale:      en
    gherkin_translations: []
    testers:
        # Sets the strict mode for result interpretation
        strict:               false
        # Tells tester to skip all tests
        skip:                 false
        # Sets the rerun cache path
        rerun_cache:          /tmp/behat_rerun_cache
    cli:                  []
    environments:         []
    specifications:       []
    filesystem:           []
    contexts:             []
    snippets:             []
    definitions:          []
    events:               []
    hooks:                []
    transformations:      []
    ordering:             []
    mink:
        mink_loader:          null
        base_url:             null
        files_path:           null
        show_auto:            false
        show_cmd:             null
        show_tmp_dir:         /tmp
        # Defaults to the first non-javascript session if any, or the first session otherwise
        default_session:      null
...

Recortamos la salida ya que el archivo nos agrega todo lo configuráble contextos,.. aunque no lo usemos.

Esta sería una configuración un poco más detallada de un archivo .yml final

Todos los path que definamos cogerán de base el directorio desde donde este nuestro archivo .yml en nuestro caso en sites/defult 

default:
  autoload:
    '': %paths.base%/[path-to-boostrap-dir]
  suites:
    default:
      paths:
        - %paths.base%/[path-to-feature-dir]
      contexts:                                                  # Contexts used
        - FeatureContext:                                        # Default
        - Drupal\DrupalExtension\Context\MinkContext:                # Context Drupal extension
        - Drupal\DrupalExtension\Context\MessageContext:
        - Drupal\DrupalExtension\Context\DrushContext:
  extensions:
    Behat\MinkExtension:
      goutte: ~
      sessions:
        default:
          goutte:
            guzzle_parameters:
              verify: false
      selenium2:
        wd_host: "http://127.0.0.1:9000/wd/hub"
      base_url: '[url-website]'
      show_cmd: lynx %s
      files_path: "%paths.base%/[path-files-dir]"  # Define path to file, use to attachment file to drupal 
    Drupal\DrupalExtension:
      blackbox: ~
      drush_driver: "drush"
      drush:
        root: "[path-run-drush]"   # Define path of being able to execute drush commands
      api_driver: "drupal"
      drupal:
        drupal_root: "[path-index-site]"  # Define path to index.php
      region_map:                               # Define region use in steps
        content: "#content"
      selectors:                                    # Use in MessageContext, define type message
        message_selector:         '.messages'
        error_message_selector:   '.messages.error'
        success_message_selector: '.messages.status'
        warning_message_selector: '.messages.warning'
      text:                                         # Default text find
        password_field: "edit-pass"
        username_field: "edit-name"
        log_in: "Iniciar sesión"
        log_out: "Cerrar sesión"

Para más información sobre las configuraciones tenemos unos artículos muy interesantes:

Configuración básica (y no tan básica) de behat 2.x para Drupal Extension

Behat 3.x y Drupal: cambios respecto a Behat 2.x

Y para terminar volveremos a ejecutar Behat pero esta vez le pasamos un parámetro --config para especificar que configuración utilizar.

behat --config=[path_to_yml]
# Example
behat --config=sites/default/default.behat.yml

Y si los pasos anteriores