Julio 09, 2015
Luis Eduardo Telaya Escobedo
- Pre-requisitos
Revisar post ¿Qué es y Cómo instalar behat?
- 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
- 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