Implementando un feature en behat

Author Top
Luis Eduardo Telaya Escobedo

0. Pre-requisitos

Revisar post ¿Qué es y Cómo instalar behat?

1. Objetivo

- Validar que nuestra app(el cual es una sencilla aplicación que suma dos valores) sea el correcto valor esperado.

Tenemos la siguiente clase:

Calculate.php con métodos setValueA, setValueB, getValueA, getValueB, Sum y getResult.

<?php

class Calculate {
  private $value_a;
  private $value_b;
  private $result;

  public function __construct() {
  }

  public function setValueA($value_a) {
    $this->value_a = $value_a;
  }

  public function setValueB($value_b) {
    $this->value_b = $value_b;
  }

  public function getValueA() {
    return $this->value_a;
  }

  public function getValueB() {
    return $this->value_b;
  }

  public function sum() {
    $this->result = $this->getValueA() + $this->getValueB();
  }

  public function getResult() {
    return $this->result;
  }
}
?>

y un archivo index.php el cual instancia Calculate y establece valores 3 y 10, los suma e imprime el valor por pantalla(el cual es 10).

<?php
include_once 'Calculate.php';

$calculate = new Calculate();
$calculate->setValueA(3);
$calculate->setValueB(7);
$calculate->sum();

print 'Result of myapp: ' . $calculate->getResult();
?>

No obstante ¿Cómo podemos validar que funcione correctamente?

En este caso usaremos behat! para validar la suma de dos números positivos. Así que vamos a escribir el feature "Addition of two numbers"

Feature: Addition of two numbers

As a student of mathematics
I want to get the sum of two numbers
To learn how to add

Scenario: Add two positive numbers
     Given I am in the application
     When I enter the numbers 7 and 3
     And I apply the calculation result
     Then the result should be 10

2. Implementación

Debemos de tener la siguiente estructura de carpetas:

├── LICENSE
├── bin
├── composer.json
├── composer.lock
├── composer.phar
├── vendor/
├── index.php
├── Calculate.php

Ahora si vamos a la raíz de nuestro proyecto veremos que hay una carpeta bin/ y adentro un archivo ejecutable behat. Ahora corremos el siguiente comando desde la raíz de nuestro proyecto:

$ bin/behat --init

Y obtendremos el siguiente resultado:

+d features - place your *.feature files here
+d features/bootstrap - place bootstrap scripts and static files here
+f features/bootstrap/FeatureContext.php - place your feature related code here

Con el comando anterior $ bin/behat --init obtendremos una estructura básica para poder colocar nuestros features.

si queremos agregar más *.features las agregamos en la carpeta features y su implementación en código php las agregamos en features/bootstrap. 

Tambien podemos ver que se ha creado features/bootstrap/FeatureContext.php es un archivo php de ejemplo donde contiene una estructura basica a implementar nuestro feature con algunos use propios de behat.

<?php

use Behat\Behat\Context\ClosuredContextInterface,
    Behat\Behat\Context\TranslatedContextInterface,
    Behat\Behat\Context\BehatContext,
    Behat\Behat\Exception\PendingException;
use Behat\Gherkin\Node\PyStringNode,
    Behat\Gherkin\Node\TableNode;

//
// Require 3rd-party libraries here:
//
//   require_once 'PHPUnit/Autoload.php';
//   require_once 'PHPUnit/Framework/Assert/Functions.php';
//

/**
 * Features context.
 */
class FeatureContext extends BehatContext
{
    /**
     * Initializes context.
     * Every scenario gets it's own context object.
     *
     * @param array $parameters context parameters (set them up through behat.yml)
     */
    public function __construct(array $parameters)
    {
        // Initialize your context here
    }

//
// Place your definition and hook methods here:
//
//    /**
//     * @Given /^I have done something with "([^"]*)"$/
//     */
//    public function iHaveDoneSomethingWith($argument)
//    {
//        doSomethingWith($argument);
//    }
//
}

Ahora vamos agregar features/Sum.feature que es donde pondremos lo siguiente:

Feature: Addition of two numbers

As a student of mathematics
I want to get the sum of two numbers
To learn how to add

Scenario: Add two positive numbers
     Given I am in the application
     When I enter the numbers 7 and 3
     And I apply the calculation result
     Then the result should be 10

Ejemplo de como estaria quedando nuestra directorio hasta el momento:

├── LICENSE
├── bin
├── composer.json
├── composer.lock
├── composer.phar
├── vendor/
├── index.php
├── Calculate.php
├── features/
├──── Sum.feature
├──────bootstrap/
├────────FeatureContext.php

Ahora necesitamos implementar cada step e.g: "When I enter the numbers 7 and 3"  necesitamos escribir código php de cada uno de estos pasos. Para esto se sigue un patron.

Por ejemplo "When I enter the numbers 7 and 3" en php seria:

    /**
     * @When /^I enter the numbers (\d+) and (\d+)$/
     */
    public function iEnterTheNumbersAnd($arg1, $arg2)
    {
        throw new PendingException();
    }

Notese que es camel case el nombre de la función y los números pasan como argumentos. Y en los comentarios tienen su propio patron. (en otro post veremos a detalle estos patrones)

Tenemos otra alternativa a estar creando uno por uno a php, el cual es desde la terminal ir a la raiz del proyecto y ejecutar el comando:

$ bin/behat

Y obtendremos lo siguiente:

Feature: Addition of two numbers

  As a student of mathematics
  I want to get the sum of two numbers
  To learn how to add

  Scenario: Add two positive numbers   # features/Sum.feature:7
    Given I am in the application
    When I enter the numbers 7 and 3
    And I apply the calculation result
    Then the result should be 11

1 scenario (1 undefined)
4 steps (4 undefined)
0m0.008s

You can implement step definitions for undefined steps with these snippets:

    /**
     * @Given /^I am in the application$/
     */
    public function iAmInTheApplication()
    {
        throw new PendingException();
    }

    /**
     * @When /^I enter the numbers (\d+) and (\d+)$/
     */
    public function iEnterTheNumbersAnd($arg1, $arg2)
    {
        throw new PendingException();
    }

    /**
     * @Given /^I apply the calculation result$/
     */
    public function iApplyTheCalculationResult()
    {
        throw new PendingException();
    }

    /**
     * @Then /^the result should be (\d+)$/
     */
    public function theResultShouldBe($arg1)
    {
        throw new PendingException();
    }

Con el comando anterior es para correr el feature pero dado que no hay ningun método implementado aún te muestra los métodos de cada paso que deberias implementar del o los escenario(s) y así evitamos estar haciendo el trabajo manualmente. Lo que tenemos que hacer es copiar y pegar los métodos en nuestra clase features/bootstrap/FeatureContext.php

Una vez copiado y pega tendriamos lo siguiente:

<?php

use Behat\Behat\Context\ClosuredContextInterface,
    Behat\Behat\Context\TranslatedContextInterface,
    Behat\Behat\Context\BehatContext,
    Behat\Behat\Exception\PendingException;
use Behat\Gherkin\Node\PyStringNode,
    Behat\Gherkin\Node\TableNode;

//
// Require 3rd-party libraries here:
//
//   require_once 'PHPUnit/Autoload.php';
//   require_once 'PHPUnit/Framework/Assert/Functions.php';
//

/**
 * Features context.
 */
class FeatureContext extends BehatContext
{
    /**
     * Initializes context.
     * Every scenario gets its own context object.
     *
     * @param array $parameters context parameters (set them up through behat.yml)
     */
    public function __construct(array $parameters)
    {
        // Initialize your context here
    }

    /**
     * @Given /^I am in the application$/
     */
    public function iAmInTheApplication()
    {
        throw new PendingException();
    }

    /**
     * @When /^I enter the numbers (\d+) and (\d+)$/
     */
    public function iEnterTheNumbersAnd($arg1, $arg2)
    {
        throw new PendingException();
    }

    /**
     * @Given /^I apply the calculation result$/
     */
    public function iApplyTheCalculationResult()
    {
        throw new PendingException();
    }

    /**
     * @Then /^the result should be (\d+)$/
     */
    public function theResultShouldBe($arg1)
    {
        throw new PendingException();
    }
}

Notese que los nombres de las funciones se genera basado en el texto de cada step escapando los numeros y aplicando el camelcase, no obstante no tienen nada implemetado aun.

El paso siguiente es escribir código en cada método de acuerdo al paso. Vamos a usar require_once para llamar a Calculate.php

en iAmInTheApplication()  vamos a instanciar el objeto $calculate = new Calculate()

iEnterTheNumbersAnd($arg1, $arg2) vamos a setear setValueA($arg1) y setValueB($arg2)

iApplyTheCalculationResult() usaremos el método sum()  

theResultShouldBe($arg1) validaremos usando getResult() si la suma fue correcta o no. Si no fuera correcta lanzaremos una exception.

Nota: los nombres de los métodos hacen match a cada step, si los modifica ya no funcionara y dara un mensaje de error.

Así quedaria nuestra clase features/bootstrap/FeatureContext.php

<?php

use Behat\Behat\Context\ClosuredContextInterface,
    Behat\Behat\Context\TranslatedContextInterface,
    Behat\Behat\Context\BehatContext,
    Behat\Behat\Exception\PendingException;
use Behat\Gherkin\Node\PyStringNode,
    Behat\Gherkin\Node\TableNode;

require_once __DIR__ . '/../../Calculate.php';

//
// Require 3rd-party libraries here:
//
//   require_once 'PHPUnit/Autoload.php';
//   require_once 'PHPUnit/Framework/Assert/Functions.php';
//

/**
 * Features context.
 */
class FeatureContext extends BehatContext
{
  public $calculate;

    /**
     * Initializes context.
     * Every scenario gets it's own context object.
     *
     * @param array $parameters context parameters (set them up through behat.yml)
     */
    public function __construct(array $parameters)
    {

    }

    /**
     * @Given /^I am in the application$/
     */
    public function iAmInTheApplication()
    {
        $this->calculate = new Calculate();
    }

    /**
     * @When /^I enter the numbers (\d+) and (\d+)$/
     */
    public function iEnterTheNumbersAnd($arg1, $arg2)
    {
      $this->calculate->setValueA($arg1);
      $this->calculate->setValueB($arg2);
    }

    /**
     * @Given /^I apply the calculation result$/
     */
    public function iApplyTheCalculationResult()
    {
      $this->calculate->sum();
    }

    /**
     * @Then /^the result should be (\d+)$/
     */
    public function theResultShouldBe($arg1)
    {
      if ($this->calculate->getResult() != $arg1) {
        throw new Exception("Error in the addition");
      }
    }
}

2.1 Test aprobado!

Ahora vamos a la raíz de nuestro proyecto corremos el siguiente comando en nuestra terminal:

$ bin/behat

Con el comando anterior va a correr la feature y va paso a paso, lee el paso 1 Dado que esto en la aplcación, cuando ingreso números 7 y 3 y calculo, luego el resultado debe ser 10. Si hubiese un paso nuevo nos indicara que debemos implementarlo y nos dara los comentarios y el nombre del método ya en camelcase listo para realizar copy & paste.

Y en nuestro caso Obtendremos:

Feature: Addition of two numbers

  As a student of mathematics
  I want to get the sum of two numbers
  To learn how to add

  Scenario: Add two positive numbers   # features/Sum.feature:7
    Given I am in the application      # FeatureContext::iAmInTheApplication()
    When I enter the numbers 7 and 3   # FeatureContext::iEnterTheNumbersAnd()
    And I apply the calculation result # FeatureContext::iApplyTheCalculationResult()
    Then the result should be 10       # FeatureContext::theResultShouldBe()

1 scenario (1 passed)
4 steps (4 passed)
0m0.007s

 Felicidades el escenario paso correctamente! quiere decir si sumamos 7 + 3 entonces dara como resultado 10

2.2 Test que falla!

Ahora haremos que el test falle

Para eso editaremos features/Sum.feature y le pondremos Then the result should be 11 en vez de 10. Así quedaria:

Feature: Addition of two numbers

As a student of mathematics
I want to get the sum of two numbers
To learn how to add

Scenario: Add two positive numbers
     Given I am in the application
     When I enter the numbers 7 and 3
     And I apply the calculation result
     Then the result should be 11

Ahora si vamos a la raíz de nuestro proyecto corremos el siguiente comando en nuestra terminal:

$ bin/behat

Obtendremos:

Feature: Addition of two numbers

  As a student of mathematics
  I want to get the sum of two numbers
  To learn how to add

  Scenario: Add two positive numbers   # features/Sum.feature:7
    Given I am in the application      # FeatureContext::iAmInTheApplication()
    When I enter the numbers 7 and 3   # FeatureContext::iEnterTheNumbersAnd()
    And I apply the calculation result # FeatureContext::iApplyTheCalculationResult()
    Then the result should be 11       # FeatureContext::theResultShouldBe()
      Error in the addition

1 scenario (1 failed)
4 steps (3 passed, 1 failed)
0m0.024s

Fallo nuestro scenario  en el paso Then the result should be 11 ya que la suma de 7 + 3 no es 11 sino 10. Lanzando la exception "Error in the addition"

y es así como implementamos behat!

Este fue un ejemplo muy sencillo de como usar behat . En otro post veremos como implementar MINK donde crearemos un ejemplo parecido pero esta vez con un formulario html donde se ingresen estos valores y otros ejemplos donde le sacaremos al máximo a behat!  además de posts integrandolo con Drupal! lo que esperaban!.

Happy codding

bursa esc
bursa eskort
bursa escort bayan bursa travesti escort bursa merkez escort bursaescort bursa escort bayanlar alanya eskort bayan antalya bayan eskort havalimanı transfer