SlideShare una empresa de Scribd logo
1 de 103
Descargar para leer sin conexión
Mink & Behat
BDD - Behaviour Driven Development
Flujo BDD
Stakeholders:
trabajadores, propietarios,
proveedores…
(cualquiera con alguna
relación con la empresa)
Es un proceso de desarrollo de software
Un tipo de TDD... pero más verboso
donde intervienen varios colaboradores (stakeholders)
¿Qué es BDD?
HISTORIA
Tipos de BDD
ESPECIFICACIONES
STORY SPEC
Tipos de BDD
Story BDD* se lleva a cabo con Behat
Enfocado en la narrativa = QUÉ
Tipos de BDD
Spec BDD se lleva a cabo con PHPSpec
Enfocado en la implementación = CÓMO
Mink & Behat
Qué es
Proyecto Open Source creado por Konstantin Kudryashov
Desarrollo albergado en GitHub: https://github.com/Behat/Behat
¿Qué es Behat?
¿Qué es Behat?
Un framework para testing en BDD (Behaviour Driven Development)
Escrito en php y para php 5.3+
Inspirado en Cucumber, de Ruby (https://cucumber.io/)
Behat 3 está considerado como la versión oficial de la implementación de
Cucumber para php y muy bien considerado en el mundo del BDD
¿Qué es Behat?
Behat usa como lenguaje para contar historias: Gherkin
Gherkin es un DSL, Domain Specific Language, como SQL
¿Qué es Behat?
Gherkin usa un lenguaje humano real estructurado
Uno modo de escribir una historia que puede ser automatizada
¿Qué es Behat?
Las sentencias se pueden escribir en varios idiomas
NO es un lenguaje de programación
¿Qué es Behat?
Promueve la comunicación entre todas las partes que intervienen en la empresa,
como por ejemplo: la parte de negocio y la parte de desarrollo
¿Por qué Behat?
Ubiquitous Language (Martin Fowler): https://martinfowler.com/bliki/UbiquitousLanguage.html
UBIQUITOUS LANGUAGE
Feature: The Coffee Machine serves coffees
In order to take a coffee
As a buyer
I should be able to buy a coffee to stay awake
Scenario: Buy one coffee
Given Coffee Machine can serve up to 10 coffees at $0.60
When I deposit 1 dollar
And I press the coffee button
Then I should be served a coffee
And I should be returned $0.40
And There should be 9 coffees left
Vamos a contar una historia
Feature: The Coffee Machine serves coffees
In order to take a coffee
As a buyer
I should be able to buy a coffee to stay awake
Scenario: Buy one coffee
Given Coffee Machine can serve up to 10 coffees at $0.60
When I deposit 1 dollar
And I press the coffee button
Then I should be served a coffee
And I should be returned $0.40
And There should be 9 coffees left
QUÉ
POR QUÉ
QUIEN
rol de usuario
Feature: The Coffee Machine serves coffees
In order to take a coffee
As a buyer
I should be able to buy a coffee to stay awake
Scenario: Buy one coffee
Given Coffee Machine can serve up to 10 coffees at $0.60
When I deposit 1 dollar
And I press the coffee button
Then I should be served a coffee
And I should be returned $0.40
And There should be 9 coffees left
1 única Feature (Historia) por archivo .feature
N Scenarios por Feature
Feature: The Coffee Machine serves coffees
In order to take a coffee
As a buyer
I should be able to buy a coffee to stay awake
Scenario: Buy one coffee
Given Coffee Machine can serve up to 10 coffees at $0.60
When I deposit 1 dollar
And I press the coffee button
Then I should be served a coffee
And I should be returned $0.40
And There should be 9 coffees left
Sentences:
Acciones/Steps
a testear
Feature: The Coffee Machine serves coffees
In order to take a coffee
As a buyer
I should be able to buy a coffee to stay awake
Scenario: Buy one coffee
Given Coffee Machine can serve up to 10 coffees at $0.60
When I deposit 1 dollar
And I press the coffee button
Then I should be served a coffee
And I should be returned $0.40
And There should be 9 coffees left
precondiciones/
inicializaciones
interacción
de usuario
resultados
¿Dónde ocurre la magia?
¿Y dónde está la implementación de los tests?
Behat “mapea” definiciones Gherkin con implementación Php y
las relaciona mediante anotaciones
Scenario Steps
.feature
acciones en Gherkin
Step Definitions
FeatureContext.php
Código PHP
/**
* @When I deposit 1 dollar
*/
public function iDepositOneDollar()
{
// do something
}
Feature: The Coffee Machine serves coffees
...
Scenario: Buy one coffee
Given ...
When I deposit 1 dollar
And ...
gherkin
.feature
FeatureContext.php
anotación + método
1.- Instalar composer
2.- Crear archivo composer.json
3.- Ejecutar composer install
{
"require-dev": {
"behat/behat": "3.3.1"
},
"config": {
"bin-dir": "bin/"
}
}
Configuración proyecto básico Behat
4.- Inicializar Behat para configurar un framework base: ./bin/behat --init
5.- Tras crear los tests ejecutar ./bin/behat
6.- Opcionalmente crear archivo behat.yml (configuración avanzada)
bin
composer.json
composer.lock
features
|_ bootstrap
|_ FeatureContext.php
vendor ...
Ubicación para los
archivos .feature
Ubicación archivos
*Context.php
Configuración proyecto básico Behat
Una puede definir uno o más Scenario
Cada testea un comportamiento
Cada puede definir uno o más Steps
Los Steps se pueden encadenar
Los Comentarios están permitidos
Given When And/But Then
Scenario
Scenario
Feature
# this is a comment
Qué define cada Keyword
Scenario Outline
Background
Given ( + table
transformation )
Examples ( + table )
Más definiciones de Keywords
Se ejecuta el mismo
Scenario para cada fila
de la tabla
Todos los Steps dentro
de Background se
iniciarán antes de cada
Scenario
Nos permite inicializar
datos para trabajar
dentro de un Scenario
Escritura de una Feature: GOOD PRACTICE
Explica QUÉ es lo que se desea hacer y NO CÓMO de modo que
todo el mundo pueda entender la situación
Pensar 2 veces antes de escribir una frase de modo que
cualquiera pueda entender el caso *
* caso usb
Indicar expresamente el valor de un elemento de formulario
Utilizar en una sentencia el valor de un id
Bad: I press the button with id “server-coffee”
Escritura de una Feature: BAD PRACTICE
Good: I press the coffee button
Escritura de una Feature: GOOD PRACTICE
Indicar cuál es la acción que se desea llevar a cabo, no cómo
Mink & Behat
Qué es
¿Qué es Mink?
Mink es un proyecto Open Source para PHP5.3+ que permite
controlar/simular un navegador web
y poder así testear aplicaciones web
El desarrollo está hospedado en GitHub: https://github.com/minkphp/Mink
Desarrollado y mantenido por varios contribuidores
¿Qué es Mink?
Con Mink es posible
Controlar el Navegador Recorrer un página
Manipular elementos
de un página
Interaccionar con
una página
Controlar el Navegador
Ej: $this->getSession()->visit(‘http://web-site.ext’);
¿Qué permite llevar a cabo Mink?
Recorrer una página
Ej: $this->getSession()->getPage()->find(‘css’, ‘h1’);
¿Qué permite llevar a cabo Mink?
Manipular elementos
de una página
Ej: $this->getSession()->getPage()->getText();
¿Qué permite llevar a cabo Mink?
Interaccionar con una
página
Ej: $this->getSession()->getPage()->findById(‘div-cta’)->click();
¿Qué permite llevar a cabo Mink?
¿Qué es Mink?
Mink provee principalmente 4 objetos
DRIVER SESSION NODE ELEMENTPAGE
DRIVER: $goutteDriver = new GoutteDriver();
SESSION: $this->getSession()
PAGE: $this->getSession()->getPage()
NODEELEMENT: $this->getSession()->getPage()->find(‘h1’)
¿Por qué Mink?
Mink implementa drivers específicos para cada Emulador Web
abstrayendo llamadas API específicas
Goutte Selenium2 Zombie
¿Por qué Mink?
Puede “lanzar navegadores”
Clientes Web con Interfaz gráfica Servidores web sin Interfaz Gráfica
Permite testear distintas resoluciones web
¿Por qué Mink?
Permite testear distintos motores de navegadores web
¿Por qué Mink?
En sistemas operativos diversos
¿Por qué Mink?
Se integra bien con “Navegadores” Web gracias a: Selenium & Sahi
Sahi package abandonado y sin mantener: https://packagist.org/packages/behat/mink-sahi-driver
¿Por qué Mink?
Es posible testear funcionalidades javascript
¿Por qué Mink?
Se puede integrar fácilmente con frameworks para Php tales como
Symfony/Laravel
¿Por qué Mink?
Ofrece un API común para todos los diferentes Emuladores Web
mediante la definición de una interfaz (contrato)
¿Por qué Mink?
2 Tipos de Emuladores Web
1.- Emuladores Web Headless (sin cabeza)
2.- Controladores Web (Browser Controllers)
Son simplemente implementaciones de especificaciones HTTP
Emuladores Web Headless
No se puede testear JS Rápidos (Goutte)
cUrl o Guzzle
Su objetivo es controlar un navegador web real
Controladores Web (Browser Controllers)
SI que puede testear JS! Lento (Selenium/Sahi)
¿Cómo funciona Mink con Selenium?
Selenium2
Chrome
Gecko
En otra terminal
se inicia una
instancia de
Selenium Server
Standalone (.jar)
el cual
Interacciona con
los motores de
navegadores
reales
directamente o vía
drivers específicosMink inicia una
sesión con un
driver específico
Este driver a su
vez se comunica
con la
aplicación/driver
específica del
navegador web
1
2
3
Emulador Web
Headless
Controlador Web
Entonces … ¿cuál es mejor?
Depende del tipo de test
Entonces … ¿cuál es mejor?
Mink & Behat
El binomio y
¿Por qué Behat y Mink?
La ecuación permite testear
el comportamiento de un proceso web completo
El binomio actúa como intermediario
Product Managers y
clientes pueden contar una
historia (mediante un
lenguaje estructurado)
De modo que los
desarrolladores pueden
entender fácilmente los
requerimientos e
implementarlos
¿Por qué Behat y Mink?
Es un modo natural de validar los
requerimientos
¿Por qué Behat y Mink?
Promueve escribir los tests antes de escribir
una línea de código
código de mejor calidad
¿Por qué Behat y Mink?
ayuda a evitar malentendidos
¿Por qué Behat y Mink?
UBIQUITOUS LANGUAGE
Navegando por Wikipedia
Mink & Behat
Ejemplo práctico
Navegando por Wikipedia
Visitar la página de Wikipedia en Inglés
Buscar la definición de Behat
Guardar las referencias en un archivo de texto
¿Qué se pretende
Dependencias (composer.json)
{
"require-dev" : {
"behat/behat": "3.1.1",
"behat/mink": "^1.6",
"behat/mink-extension" : "^2.2",
"behat/mink-goutte-driver" : "^1.2"
},
"config": { "bin-dir": "bin/" }
}
Ejemplo práctico - Scrapper
Biblioteca Mink
Integración entre Behat y Mink
* (incluye MinkContext)
Driver de Mink para Goutte
(package independiente = buena práctica)
Biblioteca Behat
Inicialización del framework Behat: ./bin/behat --init
bin
composer.json
composer.lock
features
|_ bootstrap
|_ FeatureContext.php
vendor ...
Ubicación para los
archivos .feature
Ubicación archivos
*Context.php
Ejemplo práctico - Scrapper
default:
suites:
default:
contexts:
- FeatureContext
- BehatMinkExtensionContextMinkContext
extensions:
BehatMinkExtension :
base_url: http://en.wikipedia.org
goutte: ~
Archivo de configuración behat.yml
MinkContext ofrece una
colección de Step Definitions
gratis!
Mink Extension (pegamento
entre Behat y Mink)
Ejemplo práctico - Scrapper
default | When /^(?:|I )go to (?:|the )homepage$/
default | Then /^(?:|I )should be on "(?P<page>[^"]+)"$/
default | When /^(?:|I )follow "(?P<link>(?:[^"]|")*)"$/
default | When /^(?:|I )press "(?P<button>(?:[^"]|")*)"$/
default | Then /^(?:|I )should see "(?P<text>(?:[^"]|")*)"$/
default | Then /^(?:|I )should not see "(?P<text>(?:[^"]|")*)"$/
default | When /^(?:|I )fill in "(?P<field>(?:[^"]|")*)" with "(?P<value>(?:[^"]|")*)"$/
default | Then /^print current URL$/
default | Then /^print last response$/
default | When /^(?:|I )select "(?P<option>(?:[^"]|")*)" from "(?P<select>(?:[^"]|")*)"$/
default | When /^(?:|I )check "(?P<option>(?:[^"]|")*)"$/
default | Then /^the "(?P<checkbox>(?:[^"]|")*)" checkbox should be checked$/
default | Then /^(?:|I )should see "(?P<text>(?:[^"]|")*)" in the "(?P<element>[^"]*)" element$/
Algunas Step Definitions que nos ofrece gratis Mink vía MinkContext:
$ ./bin/behat -dl
Nota: Otros contextos interesantes: Behatch, StepThroughExtension, PageObjectExtension
Visit "https://www.wikipedia.org"
and click on "English"
Navegando por Wikipedia
I am redirected to "wiki/Main_Page"
I search "behat computer" and click on "Behat (computer science)"
Navegando por Wikipedia
Save references into a text file
Navegando por Wikipedia
Feature: Scrap behat references from wikipedia
In order get behat references
As an anonymous user
I visit wikipedia behat entry and scrap the references list
@javascript
Scenario: Scrap references
Given I am on "https://www.wikipedia.org" #Given I go to homepage
Then I should see "The Free Encyclopedia"
When I follow "English"
Then the url should match "wiki/Main_Page"
And I should see "Welcome to Wikipedia,"
When I fill in "Search Wikipedia" with "behat computer"
And I press "Search Wikipedia"
And print current URL #Debug
And I follow "Behat (computer science)"
Then I should see "Behat is intended to aid communication between"
And I save references in a local storage device#Sentencia a implementar
Archivo .feature: features/wikipedia.scrapper.feature
use BehatMinkExtensionContextRawMinkContext;
class FeatureContext extends RawMinkContext implements Context, SnippetAcceptingContext
/**
* @Given /^I save references in a local storage device$/
*/
public function iSaveReferencesInALocalStorageDevice ()
{
…
}
FeatureContext.php
Requerido para obtener una
Session de Mink
/** @Given /^I save references in a local storage device$/ */
public function iSaveReferencesInALocalStorageDevice ()
{
...
}
Step Definition
propio
Método que guarda las preferencias. Paso a paso
/** @Given /^I save references in a local storage device$/ */
public function iSaveReferencesInALocalStorageDevice ()
{
$page = $this->getSession()->getPage();
...
}
Obtener el
objeto Page
Obtener el objeto
Session (pensar en
una pestaña del
navegador)
Método que guarda las preferencias. Paso a paso
/** @Given /^I save references in a local storage device$/ */
public function iSaveReferencesInALocalStorageDevice ()
{
$page = $this->getSession()->getPage();
$content = $page->find('named', array('id', 'mw-content-text' ));
}
named Selector
buscar por id
Método que guarda las preferencias. Paso a paso
/** @Given /^I save references in a local storage device$/ */
public function iSaveReferencesInALocalStorageDevice ()
{
...
$references = $content->find('css', '.references');
$items = $references->findAll('css', 'li');
}
Selectores CSS
¡Atención con el punto!
find vs findAll
Método que guarda las preferencias. Paso a paso
/** @Given /^I save references in a local storage device$/ */
public function iSaveReferencesInALocalStorageDevice ()
{
...
$links = array();
foreach ($items as $item) {
$linkContainer = $item->find('xpath', '//span[@class="reference-text"]' );
$links[] = $linkContainer ->find('xpath', '//a/@href')->getText();
}
}
Selectores xpath
obtener sólo el valor del enlace
Método que guarda las preferencias. Paso a paso
/** @Given /^I save references in a local storage device$/ */
public function iSaveReferencesInALocalStorageDevice ()
{
...
file_put_contents ('scrapped_references.txt' , join(PHP_EOL, $links));
}
Guardar el archivo en disco
Método que guarda las preferencias. Paso a paso
/** @Given /^I save references in a local storage device$/ */
public function iSaveReferencesInALocalStorageDevice ()
{
$page = $this->getSession()->getPage();
$content = $page->find('named', array('id', 'mw-content-text' ));
$references = $content->find('css', '.references');
$items = $references->findAll('css', 'li');
$links = array();
foreach ($items as $item) {
$linkContainer = $item->find('xpath', '//span[@class="reference-text"]' );
$links[] = $linkContainer ->find('xpath', '//a/@href')->getText();
}
file_put_contents ('scrapped_references.txt' , join(PHP_EOL, $links));
}
2.- Css Selectors
3.- Xpath Selectors
1.- Named Selector
Método que guarda las preferencias. Paso a paso
: implementar la misma solución con menor código
Vamos a Refactorizar
/** @Given /^I save references in a local storage device again$/ */
public function iSaveReferencesInALocalStorageDeviceAgain ()
{
$closure = function($item) { return $item->getText(); }; // anonymous function
$xpath = '//span[@class="reference-text"]/a/@href';
$links = array_map($closure, $this->findAll('xpath', $xpath));
file_put_contents ('scrapped_references_again.txt' , join(PHP_EOL, $links));
}
public function __call($method, $parameters)
{
$page = $this->getSession()->getPage();
if (method_exists($page, $method)) {
return call_user_func_array (array($page, $method), $parameters);
}
}
Magic Call
Sólo un selector xpath
Método que guarda las preferencias. Solución corta
Closure vs Lambda: https://www.ibm.com/developerworks/library/os-php-5.3new2/os-php-5.3new2-pdf.pdf
Ejecutar el test
./bin/behat
bdd# ./bin/behat
Feature: Scrap behat references from wikipedia
...
Scenario: Scrap References # features/wikipedia.scrapper.feature:6
Given I am on " https://www.wikipedia.org" # BehatMinkExtensionContextMinkContext::visit()
Then I should see " The Free Encyclopedia" # Behat...MinkContext::assertPageContainsText()
When I follow " English" # Behat...MinkContext::clickLink()
Then the url should match "wiki/Main_Page" # Behat...MinkContext::assertUrlRegExp()
And I should see " Welcome to Wikipedia," # Behat...MinkContext::assertPageContainsText()
When I fill in " Search Wikipedia" with "behat computer" # Behat...MinkContext::fillField()
And I press " Search Wikipedia" # Behat...MinkContext::pressButton()
And I follow " Behat (computer science)" # Behat...MinkContext::clickLink()
Then I should see " Behat is intended to aid communication between developers, clients and other
stakeholders during a..." # Behat...MinkContext::assertPageContainsText()
And I save references in a local storage device
# FeatureContext::iSaveReferencesInALocalStorageDevice()
1 scenario (1 passed)
10 steps (10 passed)
0m4.15s (15.36Mb)
Bonus track
Echando una mano a Mink
El flujo de ejecución de Behat está basado en eventos
Behat provee 8 Hooks de gran ayuda. Principio DRY
Los eventos se “mapean” mediante anotaciones
Las anotaciones simplifican la gestión de Datafixtures
Behat ofrece tags predefinidos (@javascript) y admite tags personalizados
feature1.feature
Gherkin
Parser
testFeature
testScenario
testStep
feature2.feature
featureN.feature
testBackground
Event
Dispatcher
Listener1
Listener2
ListenerN
...
@BeforeSuite
@BeforeFeature
@BeforeScenario
@BeforeStep
@AfterStep
@AfterScenario
@AfterFeature
@AfterSuite
...
1) Java JRE
2) Firefox, Chrome y/o otros drivers. Ver sección Third Party Drivers, Bindings,
and Plugins at http://www.seleniumhq.org/download)
3) Selenium Standalone Server (http://www.seleniumhq.org/)
4) xvfb (X Virtual Frame Buffer). Permite crear una “gráfica virtual” en memoria.
5) Servidor web integrado por PHP (bin/console server:run) o un Servidor web
con urlRewrite (Apache/nginx) y host debidamente configurado.
Imprescindibles para ejecutar los tests:
Nota: Firefox v.46 con selenium-server-standalone-2.53.1.jar funciona sin problemas
En resumen:
$ ./bin/behat --config ./app/config/behat.yml
$ ./bin/console server:start
$ java -jar ./bin/selenium-server-standalone-2.53.1.jar (see ./scripts/start-selenium.sh)
$ sudo Xvfb :10 -ac
Y finalmente:
Imprescindibles para ejecutar los tests:
Caso de Uso www.takeachef.com
Caso de Uso www.takeachef.com
I follow “Empezar”
Existe otro “EMPEZAR”
más abajo, se actuará
sobre el primero que
encuentre
I follow “EMPEZAR”
Internamente en findAll, dentro de Element.php se
monta el siguiente xpath:
//html/.//a[./@href][((./@id = 'EMPEZAR' or
normalize-space(string(.)) = 'EMPEZAR' or ./@title = 'EMPEZAR'
or ./@rel = 'EMPEZAR') or .//img[./@alt = 'EMPEZAR'])] |
//html/.//*[translate(./@role,'ABCDEFGHIJKLMNOPQRSTUVWX
YZ', 'abcdefghijklmnopqrstuvwxyz') = 'link'][((./@id = 'EMPEZAR'
or ./@value = 'EMPEZAR') or ./@title = 'EMPEZAR' or
normalize-space(string(.)) = 'EMPEZAR')]
Caso de Uso
Caso de Uso
El driver que utilizamos en
Mink es Selenium2
Éste a su vez interactúa
con el driver de Firefox.
Utilizaremos la anotación
@javascript ya que el
asistente sólo funciona con
Javascript
En Selenium Server
Standalone Server 3.* el
driver de Firefox a utilizar es
Gecko
Caso de Uso
I should see “Encuentra tu Chef”
I should see “ENCUENTRA TU CHEF”
El tratamiento interno que hace Mink no
siempre es el mismo. En este caso
MinkContext llama al método de
pagetTextContains el cual busca el texto
mediante una expresión regular
preg_match
Caso de Uso
I click “Continuar”
Debido a un efecto delay en css:
- Hay un hook en BeforeStep,
que espera a que el contenedor
esté del todo visible, utiliza
función spins (alternativa: wait)
- Hay creado 1 Step Definition
propio para que busque el texto
sobre el contenedor que esté
activo y visible
Para interacciones donde la respuesta no es inmediata
Mink ofrece el método wait
$this->getSession()->wait($seconds);
No se considera una buena práctica la espera de
un número determinado de segundos
Pasar una evaluación Javascript es mucho mejor
La comprobación se realiza cada 100 ms hasta un tiempo máximo
expresamente definido
// wait for n milliseconds until JS expression becomes true:
$session->wait(
5000,
"$('.suggestions-results').children().length"
);
Espera a que la expresión javascript
retorne verdadero hasta 5 segundos
public function spins($closure, $seconds = 5, $fraction = 4)
{
$max = $seconds * $fraction;
$i = 1;
while ($i++ <= $max) {
if ($closure($this)) {
return true;
}
$this->getSession()->wait(1000 / $fraction);
}
$backtrace = debug_backtrace();
throw new Exception(
sprintf("Timeout thrown by %s::%s()n%s, line %s" ,
$backtrace[0]['class'], $backtrace[0]['function'],
$backtrace[0]['file'], $backtrace[0]['line']
)
);
}
Timeout 5s por defecto
Fracción de segundo
En casos más complejos o por claridad de código. Función “propia” spins:
Caso de Uso
I fill in the address “Castellón”
En este caso:
- Hay creado 1 Step Definition
propio para gestionar las
direcciones que ofrece la Api de
GoogleMaps.
- También se contempla la función
Spins ya que la carga de datos del
desplegable es asíncrona y
requiere un tiempo indeterminado
Caso de Uso
I click on “2 personas”
I click on “13+ personas desde 35€”
fallará ya que el texto está incluido
en 2 elementos distintos
Caso de Uso
I click on “Quiero dejarme”
I click on “wizard.preferences.surprise”
No hace falta escribir todo el texto
“Quiero dejarme sorprender” aunque
es aconsejable
No usar nunca la key de traducciones
e internamente llamar al servicio
translate o similar del framework
utilizado, puede dar falsos positivos
Caso de Uso
I click on “Enviar”
Finalizamos el proceso
Aparecerá un loader, en este caso
no hace falta utilizar la función
spins ya que no utilizamos ajax,
aunque lo pueda parecer.
Mink se encarga de esperar a que
se cargue la página
correspondiente al enlace clicado.
Caso de Uso
I should see “¡Nuestros chefs ya están
cocinando tu menú!
Creamos un Step Definition propio y
comprobamos que en base de datos se
guardan los datos que hemos introducido en
el test correctamente:
- Solicitud con los datos del test
- Creación de usuario
- Envío de e-mails de confirmación
- Derivación a Chefs (dados de alta
anteriormente mediante DataFixtures)
Práctica discutible, en ocasiones vale la pena ser prácticos
Samuel Vicent Pitarch
samuelvicent@gmail.com
https://www.linkedin.com/in/samuelvicent/
https://twitter.com/samuelvicent
www.geekshubsacademy.com www.takeachef.com

Más contenido relacionado

Similar a BDD Behat Mink Wikipedia

Automatización de interfaces e introducción a bdd
Automatización de interfaces e introducción a bddAutomatización de interfaces e introducción a bdd
Automatización de interfaces e introducción a bddJorge Ortiz
 
Desymfony 2011 - Tutorial #1: Instalacion y primeros pasos
Desymfony 2011 - Tutorial #1: Instalacion y primeros pasosDesymfony 2011 - Tutorial #1: Instalacion y primeros pasos
Desymfony 2011 - Tutorial #1: Instalacion y primeros pasosJavier Eguiluz
 
Charla Hello Real World para PHPmad
Charla Hello Real World para PHPmadCharla Hello Real World para PHPmad
Charla Hello Real World para PHPmadsenechaux
 
Tech day#7 – especificaciones_ejecutables_y_BDD_con_cucumber_y_selenium
Tech day#7 – especificaciones_ejecutables_y_BDD_con_cucumber_y_seleniumTech day#7 – especificaciones_ejecutables_y_BDD_con_cucumber_y_selenium
Tech day#7 – especificaciones_ejecutables_y_BDD_con_cucumber_y_seleniumEduardo Riol
 
Tutorial CodeIgniter + Netbeans 7
Tutorial CodeIgniter + Netbeans 7Tutorial CodeIgniter + Netbeans 7
Tutorial CodeIgniter + Netbeans 7Juan Fede
 
Meterpreter en android el desembarco en tu smartphone
Meterpreter en android   el desembarco en tu smartphoneMeterpreter en android   el desembarco en tu smartphone
Meterpreter en android el desembarco en tu smartphoneJASENT
 
Webutil 090812113116-phpapp01
Webutil 090812113116-phpapp01Webutil 090812113116-phpapp01
Webutil 090812113116-phpapp01emonsalve
 
¡Que lo haga otro! Automatizaciones SEO para vivir mejor
¡Que lo haga otro! Automatizaciones SEO para vivir mejor¡Que lo haga otro! Automatizaciones SEO para vivir mejor
¡Que lo haga otro! Automatizaciones SEO para vivir mejorIñaki Huerta (ikhuerta)
 
Desarrollo de aplicaciones multiplataforma 1/2
Desarrollo de aplicaciones multiplataforma 1/2Desarrollo de aplicaciones multiplataforma 1/2
Desarrollo de aplicaciones multiplataforma 1/2Ignacio Muñoz Vicente
 
Curso TDD Ruby on Rails #02: Test Driven Development
Curso TDD  Ruby on Rails #02: Test Driven DevelopmentCurso TDD  Ruby on Rails #02: Test Driven Development
Curso TDD Ruby on Rails #02: Test Driven DevelopmentAlberto Perdomo
 
Progressive web apps
Progressive web apps Progressive web apps
Progressive web apps Biko
 
Primeros pasos con Backbone js, por Xavier Aznar
Primeros pasos con Backbone js, por Xavier AznarPrimeros pasos con Backbone js, por Xavier Aznar
Primeros pasos con Backbone js, por Xavier AznarPablo Aguilera
 
Consumo de APIs usando el WSO2 API Manager
Consumo de APIs usando el WSO2 API ManagerConsumo de APIs usando el WSO2 API Manager
Consumo de APIs usando el WSO2 API ManagerIsildurMaC
 
Zend Framework Taller de SeeD Software, Colombia
Zend Framework Taller de SeeD Software, ColombiaZend Framework Taller de SeeD Software, Colombia
Zend Framework Taller de SeeD Software, Colombiarazigal
 

Similar a BDD Behat Mink Wikipedia (20)

Automatización de interfaces e introducción a bdd
Automatización de interfaces e introducción a bddAutomatización de interfaces e introducción a bdd
Automatización de interfaces e introducción a bdd
 
Desymfony 2011 - Tutorial #1: Instalacion y primeros pasos
Desymfony 2011 - Tutorial #1: Instalacion y primeros pasosDesymfony 2011 - Tutorial #1: Instalacion y primeros pasos
Desymfony 2011 - Tutorial #1: Instalacion y primeros pasos
 
Charla Hello Real World para PHPmad
Charla Hello Real World para PHPmadCharla Hello Real World para PHPmad
Charla Hello Real World para PHPmad
 
DotNetDom: El futuro de Xamarin
DotNetDom: El futuro de XamarinDotNetDom: El futuro de Xamarin
DotNetDom: El futuro de Xamarin
 
Tech day#7 – especificaciones_ejecutables_y_BDD_con_cucumber_y_selenium
Tech day#7 – especificaciones_ejecutables_y_BDD_con_cucumber_y_seleniumTech day#7 – especificaciones_ejecutables_y_BDD_con_cucumber_y_selenium
Tech day#7 – especificaciones_ejecutables_y_BDD_con_cucumber_y_selenium
 
Tutorial CodeIgniter + Netbeans 7
Tutorial CodeIgniter + Netbeans 7Tutorial CodeIgniter + Netbeans 7
Tutorial CodeIgniter + Netbeans 7
 
Meterpreter en android el desembarco en tu smartphone
Meterpreter en android   el desembarco en tu smartphoneMeterpreter en android   el desembarco en tu smartphone
Meterpreter en android el desembarco en tu smartphone
 
Webutil
WebutilWebutil
Webutil
 
Webutil
WebutilWebutil
Webutil
 
Webutil 090812113116-phpapp01
Webutil 090812113116-phpapp01Webutil 090812113116-phpapp01
Webutil 090812113116-phpapp01
 
Workshop calabash appium
Workshop calabash appiumWorkshop calabash appium
Workshop calabash appium
 
¡Que lo haga otro! Automatizaciones SEO para vivir mejor
¡Que lo haga otro! Automatizaciones SEO para vivir mejor¡Que lo haga otro! Automatizaciones SEO para vivir mejor
¡Que lo haga otro! Automatizaciones SEO para vivir mejor
 
Charla ie
Charla ieCharla ie
Charla ie
 
Desarrollo de aplicaciones multiplataforma 1/2
Desarrollo de aplicaciones multiplataforma 1/2Desarrollo de aplicaciones multiplataforma 1/2
Desarrollo de aplicaciones multiplataforma 1/2
 
Workshop Calabash Appium
Workshop Calabash AppiumWorkshop Calabash Appium
Workshop Calabash Appium
 
Curso TDD Ruby on Rails #02: Test Driven Development
Curso TDD  Ruby on Rails #02: Test Driven DevelopmentCurso TDD  Ruby on Rails #02: Test Driven Development
Curso TDD Ruby on Rails #02: Test Driven Development
 
Progressive web apps
Progressive web apps Progressive web apps
Progressive web apps
 
Primeros pasos con Backbone js, por Xavier Aznar
Primeros pasos con Backbone js, por Xavier AznarPrimeros pasos con Backbone js, por Xavier Aznar
Primeros pasos con Backbone js, por Xavier Aznar
 
Consumo de APIs usando el WSO2 API Manager
Consumo de APIs usando el WSO2 API ManagerConsumo de APIs usando el WSO2 API Manager
Consumo de APIs usando el WSO2 API Manager
 
Zend Framework Taller de SeeD Software, Colombia
Zend Framework Taller de SeeD Software, ColombiaZend Framework Taller de SeeD Software, Colombia
Zend Framework Taller de SeeD Software, Colombia
 

Último

Enrique Amarista Graterol - eCommerce Day Chile 2024
Enrique Amarista Graterol - eCommerce Day Chile 2024Enrique Amarista Graterol - eCommerce Day Chile 2024
Enrique Amarista Graterol - eCommerce Day Chile 2024eCommerce Institute
 
Mercedes Tomas, Florencia Bianchini - eCommerce Day Chile 2024
Mercedes Tomas, Florencia Bianchini - eCommerce Day Chile 2024Mercedes Tomas, Florencia Bianchini - eCommerce Day Chile 2024
Mercedes Tomas, Florencia Bianchini - eCommerce Day Chile 2024eCommerce Institute
 
Nicolás von Graevenitz, Rodrigo Guajardo, Fabián Müller, Alberto Banano Pardo...
Nicolás von Graevenitz, Rodrigo Guajardo, Fabián Müller, Alberto Banano Pardo...Nicolás von Graevenitz, Rodrigo Guajardo, Fabián Müller, Alberto Banano Pardo...
Nicolás von Graevenitz, Rodrigo Guajardo, Fabián Müller, Alberto Banano Pardo...eCommerce Institute
 
Presupuesto por Resultados de Seguridad Ciudadana .pptx
Presupuesto por Resultados de Seguridad Ciudadana .pptxPresupuesto por Resultados de Seguridad Ciudadana .pptx
Presupuesto por Resultados de Seguridad Ciudadana .pptxhugogabrielac1
 
Act#3.2_Investigación_Bibliográfica_Comunicación_Equipo.pdf
Act#3.2_Investigación_Bibliográfica_Comunicación_Equipo.pdfAct#3.2_Investigación_Bibliográfica_Comunicación_Equipo.pdf
Act#3.2_Investigación_Bibliográfica_Comunicación_Equipo.pdfXimenaGonzlez95
 
José Ignacio Calle, Nathalie Jacobs - eCommerce Day Chile 2024
José Ignacio Calle, Nathalie Jacobs - eCommerce Day Chile 2024José Ignacio Calle, Nathalie Jacobs - eCommerce Day Chile 2024
José Ignacio Calle, Nathalie Jacobs - eCommerce Day Chile 2024eCommerce Institute
 
CURSO DE INICIACIÓN Á ASTRONOMÍA Eclipses na Coruña
CURSO DE INICIACIÓN Á ASTRONOMÍA Eclipses na CoruñaCURSO DE INICIACIÓN Á ASTRONOMÍA Eclipses na Coruña
CURSO DE INICIACIÓN Á ASTRONOMÍA Eclipses na Coruñaanoiteenecesaria
 
CURSO DE INICIACIÓN Á ASTRONOMÍA: O noso lugar no universo
CURSO DE INICIACIÓN Á ASTRONOMÍA: O noso lugar no universoCURSO DE INICIACIÓN Á ASTRONOMÍA: O noso lugar no universo
CURSO DE INICIACIÓN Á ASTRONOMÍA: O noso lugar no universoanoiteenecesaria
 
Felipe González - eCommerce Day Chile 2024
Felipe González - eCommerce Day Chile 2024Felipe González - eCommerce Day Chile 2024
Felipe González - eCommerce Day Chile 2024eCommerce Institute
 
PRESENTACION EN SST, plan de trabajo del sistema de seguridad y salud en el t...
PRESENTACION EN SST, plan de trabajo del sistema de seguridad y salud en el t...PRESENTACION EN SST, plan de trabajo del sistema de seguridad y salud en el t...
PRESENTACION EN SST, plan de trabajo del sistema de seguridad y salud en el t...angierangel29072017
 
Guiaparacrearslideshareticsvirtual2024abril
Guiaparacrearslideshareticsvirtual2024abrilGuiaparacrearslideshareticsvirtual2024abril
Guiaparacrearslideshareticsvirtual2024abriljulianagomezm2
 
Sebastián Iturriaga - eCommerce Day Chile 2024
Sebastián Iturriaga - eCommerce Day Chile 2024Sebastián Iturriaga - eCommerce Day Chile 2024
Sebastián Iturriaga - eCommerce Day Chile 2024eCommerce Institute
 
Pablo Scasso - eCommerce Day Chile 2024
Pablo Scasso -  eCommerce Day Chile 2024Pablo Scasso -  eCommerce Day Chile 2024
Pablo Scasso - eCommerce Day Chile 2024eCommerce Institute
 
Introduccion al Libro de Genesis - Caps 15 al 17.pdf
Introduccion al Libro de Genesis - Caps 15 al 17.pdfIntroduccion al Libro de Genesis - Caps 15 al 17.pdf
Introduccion al Libro de Genesis - Caps 15 al 17.pdfDaniel425270
 
Alexander Rubilar, Enzo Tapia - eCommerce Day Chile 2024
Alexander Rubilar, Enzo Tapia - eCommerce Day Chile 2024Alexander Rubilar, Enzo Tapia - eCommerce Day Chile 2024
Alexander Rubilar, Enzo Tapia - eCommerce Day Chile 2024eCommerce Institute
 
Francisco Irarrazaval, Marcos Pueyrredon - eCommerce Day Chile 2024
Francisco Irarrazaval, Marcos Pueyrredon - eCommerce Day Chile 2024Francisco Irarrazaval, Marcos Pueyrredon - eCommerce Day Chile 2024
Francisco Irarrazaval, Marcos Pueyrredon - eCommerce Day Chile 2024eCommerce Institute
 
Suiwen He - eCommerce Day Chile 2024
Suiwen He  -  eCommerce  Day  Chile 2024Suiwen He  -  eCommerce  Day  Chile 2024
Suiwen He - eCommerce Day Chile 2024eCommerce Institute
 

Último (18)

Enrique Amarista Graterol - eCommerce Day Chile 2024
Enrique Amarista Graterol - eCommerce Day Chile 2024Enrique Amarista Graterol - eCommerce Day Chile 2024
Enrique Amarista Graterol - eCommerce Day Chile 2024
 
Mercedes Tomas, Florencia Bianchini - eCommerce Day Chile 2024
Mercedes Tomas, Florencia Bianchini - eCommerce Day Chile 2024Mercedes Tomas, Florencia Bianchini - eCommerce Day Chile 2024
Mercedes Tomas, Florencia Bianchini - eCommerce Day Chile 2024
 
Nicolás von Graevenitz, Rodrigo Guajardo, Fabián Müller, Alberto Banano Pardo...
Nicolás von Graevenitz, Rodrigo Guajardo, Fabián Müller, Alberto Banano Pardo...Nicolás von Graevenitz, Rodrigo Guajardo, Fabián Müller, Alberto Banano Pardo...
Nicolás von Graevenitz, Rodrigo Guajardo, Fabián Müller, Alberto Banano Pardo...
 
Presupuesto por Resultados de Seguridad Ciudadana .pptx
Presupuesto por Resultados de Seguridad Ciudadana .pptxPresupuesto por Resultados de Seguridad Ciudadana .pptx
Presupuesto por Resultados de Seguridad Ciudadana .pptx
 
Act#3.2_Investigación_Bibliográfica_Comunicación_Equipo.pdf
Act#3.2_Investigación_Bibliográfica_Comunicación_Equipo.pdfAct#3.2_Investigación_Bibliográfica_Comunicación_Equipo.pdf
Act#3.2_Investigación_Bibliográfica_Comunicación_Equipo.pdf
 
José Ignacio Calle, Nathalie Jacobs - eCommerce Day Chile 2024
José Ignacio Calle, Nathalie Jacobs - eCommerce Day Chile 2024José Ignacio Calle, Nathalie Jacobs - eCommerce Day Chile 2024
José Ignacio Calle, Nathalie Jacobs - eCommerce Day Chile 2024
 
CURSO DE INICIACIÓN Á ASTRONOMÍA Eclipses na Coruña
CURSO DE INICIACIÓN Á ASTRONOMÍA Eclipses na CoruñaCURSO DE INICIACIÓN Á ASTRONOMÍA Eclipses na Coruña
CURSO DE INICIACIÓN Á ASTRONOMÍA Eclipses na Coruña
 
CURSO DE INICIACIÓN Á ASTRONOMÍA: O noso lugar no universo
CURSO DE INICIACIÓN Á ASTRONOMÍA: O noso lugar no universoCURSO DE INICIACIÓN Á ASTRONOMÍA: O noso lugar no universo
CURSO DE INICIACIÓN Á ASTRONOMÍA: O noso lugar no universo
 
Felipe González - eCommerce Day Chile 2024
Felipe González - eCommerce Day Chile 2024Felipe González - eCommerce Day Chile 2024
Felipe González - eCommerce Day Chile 2024
 
PRESENTACION EN SST, plan de trabajo del sistema de seguridad y salud en el t...
PRESENTACION EN SST, plan de trabajo del sistema de seguridad y salud en el t...PRESENTACION EN SST, plan de trabajo del sistema de seguridad y salud en el t...
PRESENTACION EN SST, plan de trabajo del sistema de seguridad y salud en el t...
 
Biomecánica y análisis de puestos trabajo pptx
Biomecánica y análisis de puestos trabajo pptxBiomecánica y análisis de puestos trabajo pptx
Biomecánica y análisis de puestos trabajo pptx
 
Guiaparacrearslideshareticsvirtual2024abril
Guiaparacrearslideshareticsvirtual2024abrilGuiaparacrearslideshareticsvirtual2024abril
Guiaparacrearslideshareticsvirtual2024abril
 
Sebastián Iturriaga - eCommerce Day Chile 2024
Sebastián Iturriaga - eCommerce Day Chile 2024Sebastián Iturriaga - eCommerce Day Chile 2024
Sebastián Iturriaga - eCommerce Day Chile 2024
 
Pablo Scasso - eCommerce Day Chile 2024
Pablo Scasso -  eCommerce Day Chile 2024Pablo Scasso -  eCommerce Day Chile 2024
Pablo Scasso - eCommerce Day Chile 2024
 
Introduccion al Libro de Genesis - Caps 15 al 17.pdf
Introduccion al Libro de Genesis - Caps 15 al 17.pdfIntroduccion al Libro de Genesis - Caps 15 al 17.pdf
Introduccion al Libro de Genesis - Caps 15 al 17.pdf
 
Alexander Rubilar, Enzo Tapia - eCommerce Day Chile 2024
Alexander Rubilar, Enzo Tapia - eCommerce Day Chile 2024Alexander Rubilar, Enzo Tapia - eCommerce Day Chile 2024
Alexander Rubilar, Enzo Tapia - eCommerce Day Chile 2024
 
Francisco Irarrazaval, Marcos Pueyrredon - eCommerce Day Chile 2024
Francisco Irarrazaval, Marcos Pueyrredon - eCommerce Day Chile 2024Francisco Irarrazaval, Marcos Pueyrredon - eCommerce Day Chile 2024
Francisco Irarrazaval, Marcos Pueyrredon - eCommerce Day Chile 2024
 
Suiwen He - eCommerce Day Chile 2024
Suiwen He  -  eCommerce  Day  Chile 2024Suiwen He  -  eCommerce  Day  Chile 2024
Suiwen He - eCommerce Day Chile 2024
 

BDD Behat Mink Wikipedia

  • 1. Mink & Behat BDD - Behaviour Driven Development
  • 3. Es un proceso de desarrollo de software Un tipo de TDD... pero más verboso donde intervienen varios colaboradores (stakeholders) ¿Qué es BDD?
  • 5. Tipos de BDD Story BDD* se lleva a cabo con Behat Enfocado en la narrativa = QUÉ
  • 6. Tipos de BDD Spec BDD se lleva a cabo con PHPSpec Enfocado en la implementación = CÓMO
  • 8. Proyecto Open Source creado por Konstantin Kudryashov Desarrollo albergado en GitHub: https://github.com/Behat/Behat ¿Qué es Behat?
  • 9. ¿Qué es Behat? Un framework para testing en BDD (Behaviour Driven Development) Escrito en php y para php 5.3+
  • 10. Inspirado en Cucumber, de Ruby (https://cucumber.io/) Behat 3 está considerado como la versión oficial de la implementación de Cucumber para php y muy bien considerado en el mundo del BDD ¿Qué es Behat?
  • 11. Behat usa como lenguaje para contar historias: Gherkin Gherkin es un DSL, Domain Specific Language, como SQL ¿Qué es Behat?
  • 12. Gherkin usa un lenguaje humano real estructurado Uno modo de escribir una historia que puede ser automatizada ¿Qué es Behat?
  • 13. Las sentencias se pueden escribir en varios idiomas NO es un lenguaje de programación ¿Qué es Behat?
  • 14. Promueve la comunicación entre todas las partes que intervienen en la empresa, como por ejemplo: la parte de negocio y la parte de desarrollo ¿Por qué Behat? Ubiquitous Language (Martin Fowler): https://martinfowler.com/bliki/UbiquitousLanguage.html UBIQUITOUS LANGUAGE
  • 15. Feature: The Coffee Machine serves coffees In order to take a coffee As a buyer I should be able to buy a coffee to stay awake Scenario: Buy one coffee Given Coffee Machine can serve up to 10 coffees at $0.60 When I deposit 1 dollar And I press the coffee button Then I should be served a coffee And I should be returned $0.40 And There should be 9 coffees left Vamos a contar una historia
  • 16. Feature: The Coffee Machine serves coffees In order to take a coffee As a buyer I should be able to buy a coffee to stay awake Scenario: Buy one coffee Given Coffee Machine can serve up to 10 coffees at $0.60 When I deposit 1 dollar And I press the coffee button Then I should be served a coffee And I should be returned $0.40 And There should be 9 coffees left QUÉ POR QUÉ QUIEN rol de usuario
  • 17. Feature: The Coffee Machine serves coffees In order to take a coffee As a buyer I should be able to buy a coffee to stay awake Scenario: Buy one coffee Given Coffee Machine can serve up to 10 coffees at $0.60 When I deposit 1 dollar And I press the coffee button Then I should be served a coffee And I should be returned $0.40 And There should be 9 coffees left 1 única Feature (Historia) por archivo .feature N Scenarios por Feature
  • 18. Feature: The Coffee Machine serves coffees In order to take a coffee As a buyer I should be able to buy a coffee to stay awake Scenario: Buy one coffee Given Coffee Machine can serve up to 10 coffees at $0.60 When I deposit 1 dollar And I press the coffee button Then I should be served a coffee And I should be returned $0.40 And There should be 9 coffees left Sentences: Acciones/Steps a testear
  • 19. Feature: The Coffee Machine serves coffees In order to take a coffee As a buyer I should be able to buy a coffee to stay awake Scenario: Buy one coffee Given Coffee Machine can serve up to 10 coffees at $0.60 When I deposit 1 dollar And I press the coffee button Then I should be served a coffee And I should be returned $0.40 And There should be 9 coffees left precondiciones/ inicializaciones interacción de usuario resultados
  • 20. ¿Dónde ocurre la magia? ¿Y dónde está la implementación de los tests?
  • 21. Behat “mapea” definiciones Gherkin con implementación Php y las relaciona mediante anotaciones Scenario Steps .feature acciones en Gherkin Step Definitions FeatureContext.php Código PHP
  • 22. /** * @When I deposit 1 dollar */ public function iDepositOneDollar() { // do something } Feature: The Coffee Machine serves coffees ... Scenario: Buy one coffee Given ... When I deposit 1 dollar And ... gherkin .feature FeatureContext.php anotación + método
  • 23. 1.- Instalar composer 2.- Crear archivo composer.json 3.- Ejecutar composer install { "require-dev": { "behat/behat": "3.3.1" }, "config": { "bin-dir": "bin/" } } Configuración proyecto básico Behat
  • 24. 4.- Inicializar Behat para configurar un framework base: ./bin/behat --init 5.- Tras crear los tests ejecutar ./bin/behat 6.- Opcionalmente crear archivo behat.yml (configuración avanzada) bin composer.json composer.lock features |_ bootstrap |_ FeatureContext.php vendor ... Ubicación para los archivos .feature Ubicación archivos *Context.php Configuración proyecto básico Behat
  • 25. Una puede definir uno o más Scenario Cada testea un comportamiento Cada puede definir uno o más Steps Los Steps se pueden encadenar Los Comentarios están permitidos Given When And/But Then Scenario Scenario Feature # this is a comment Qué define cada Keyword
  • 26. Scenario Outline Background Given ( + table transformation ) Examples ( + table ) Más definiciones de Keywords Se ejecuta el mismo Scenario para cada fila de la tabla Todos los Steps dentro de Background se iniciarán antes de cada Scenario Nos permite inicializar datos para trabajar dentro de un Scenario
  • 27. Escritura de una Feature: GOOD PRACTICE Explica QUÉ es lo que se desea hacer y NO CÓMO de modo que todo el mundo pueda entender la situación Pensar 2 veces antes de escribir una frase de modo que cualquiera pueda entender el caso * * caso usb
  • 28. Indicar expresamente el valor de un elemento de formulario Utilizar en una sentencia el valor de un id Bad: I press the button with id “server-coffee” Escritura de una Feature: BAD PRACTICE
  • 29. Good: I press the coffee button Escritura de una Feature: GOOD PRACTICE Indicar cuál es la acción que se desea llevar a cabo, no cómo
  • 31. ¿Qué es Mink? Mink es un proyecto Open Source para PHP5.3+ que permite controlar/simular un navegador web y poder así testear aplicaciones web
  • 32. El desarrollo está hospedado en GitHub: https://github.com/minkphp/Mink Desarrollado y mantenido por varios contribuidores ¿Qué es Mink?
  • 33. Con Mink es posible Controlar el Navegador Recorrer un página Manipular elementos de un página Interaccionar con una página
  • 34. Controlar el Navegador Ej: $this->getSession()->visit(‘http://web-site.ext’); ¿Qué permite llevar a cabo Mink?
  • 35. Recorrer una página Ej: $this->getSession()->getPage()->find(‘css’, ‘h1’); ¿Qué permite llevar a cabo Mink?
  • 36. Manipular elementos de una página Ej: $this->getSession()->getPage()->getText(); ¿Qué permite llevar a cabo Mink?
  • 37. Interaccionar con una página Ej: $this->getSession()->getPage()->findById(‘div-cta’)->click(); ¿Qué permite llevar a cabo Mink?
  • 38. ¿Qué es Mink? Mink provee principalmente 4 objetos DRIVER SESSION NODE ELEMENTPAGE
  • 39. DRIVER: $goutteDriver = new GoutteDriver(); SESSION: $this->getSession() PAGE: $this->getSession()->getPage() NODEELEMENT: $this->getSession()->getPage()->find(‘h1’)
  • 40. ¿Por qué Mink? Mink implementa drivers específicos para cada Emulador Web abstrayendo llamadas API específicas Goutte Selenium2 Zombie
  • 41. ¿Por qué Mink? Puede “lanzar navegadores” Clientes Web con Interfaz gráfica Servidores web sin Interfaz Gráfica
  • 42. Permite testear distintas resoluciones web ¿Por qué Mink?
  • 43. Permite testear distintos motores de navegadores web ¿Por qué Mink?
  • 44. En sistemas operativos diversos ¿Por qué Mink?
  • 45. Se integra bien con “Navegadores” Web gracias a: Selenium & Sahi Sahi package abandonado y sin mantener: https://packagist.org/packages/behat/mink-sahi-driver ¿Por qué Mink?
  • 46. Es posible testear funcionalidades javascript ¿Por qué Mink?
  • 47. Se puede integrar fácilmente con frameworks para Php tales como Symfony/Laravel ¿Por qué Mink?
  • 48. Ofrece un API común para todos los diferentes Emuladores Web mediante la definición de una interfaz (contrato) ¿Por qué Mink?
  • 49. 2 Tipos de Emuladores Web 1.- Emuladores Web Headless (sin cabeza) 2.- Controladores Web (Browser Controllers)
  • 50. Son simplemente implementaciones de especificaciones HTTP Emuladores Web Headless No se puede testear JS Rápidos (Goutte) cUrl o Guzzle
  • 51. Su objetivo es controlar un navegador web real Controladores Web (Browser Controllers) SI que puede testear JS! Lento (Selenium/Sahi)
  • 52. ¿Cómo funciona Mink con Selenium? Selenium2 Chrome Gecko En otra terminal se inicia una instancia de Selenium Server Standalone (.jar) el cual Interacciona con los motores de navegadores reales directamente o vía drivers específicosMink inicia una sesión con un driver específico Este driver a su vez se comunica con la aplicación/driver específica del navegador web 1 2 3
  • 54. Depende del tipo de test Entonces … ¿cuál es mejor?
  • 55. Mink & Behat El binomio y
  • 56. ¿Por qué Behat y Mink? La ecuación permite testear el comportamiento de un proceso web completo
  • 57. El binomio actúa como intermediario Product Managers y clientes pueden contar una historia (mediante un lenguaje estructurado) De modo que los desarrolladores pueden entender fácilmente los requerimientos e implementarlos ¿Por qué Behat y Mink?
  • 58. Es un modo natural de validar los requerimientos ¿Por qué Behat y Mink? Promueve escribir los tests antes de escribir una línea de código
  • 59. código de mejor calidad ¿Por qué Behat y Mink?
  • 60. ayuda a evitar malentendidos ¿Por qué Behat y Mink? UBIQUITOUS LANGUAGE
  • 61. Navegando por Wikipedia Mink & Behat Ejemplo práctico
  • 62. Navegando por Wikipedia Visitar la página de Wikipedia en Inglés Buscar la definición de Behat Guardar las referencias en un archivo de texto ¿Qué se pretende
  • 63. Dependencias (composer.json) { "require-dev" : { "behat/behat": "3.1.1", "behat/mink": "^1.6", "behat/mink-extension" : "^2.2", "behat/mink-goutte-driver" : "^1.2" }, "config": { "bin-dir": "bin/" } } Ejemplo práctico - Scrapper Biblioteca Mink Integración entre Behat y Mink * (incluye MinkContext) Driver de Mink para Goutte (package independiente = buena práctica) Biblioteca Behat
  • 64. Inicialización del framework Behat: ./bin/behat --init bin composer.json composer.lock features |_ bootstrap |_ FeatureContext.php vendor ... Ubicación para los archivos .feature Ubicación archivos *Context.php Ejemplo práctico - Scrapper
  • 65. default: suites: default: contexts: - FeatureContext - BehatMinkExtensionContextMinkContext extensions: BehatMinkExtension : base_url: http://en.wikipedia.org goutte: ~ Archivo de configuración behat.yml MinkContext ofrece una colección de Step Definitions gratis! Mink Extension (pegamento entre Behat y Mink) Ejemplo práctico - Scrapper
  • 66. default | When /^(?:|I )go to (?:|the )homepage$/ default | Then /^(?:|I )should be on "(?P<page>[^"]+)"$/ default | When /^(?:|I )follow "(?P<link>(?:[^"]|")*)"$/ default | When /^(?:|I )press "(?P<button>(?:[^"]|")*)"$/ default | Then /^(?:|I )should see "(?P<text>(?:[^"]|")*)"$/ default | Then /^(?:|I )should not see "(?P<text>(?:[^"]|")*)"$/ default | When /^(?:|I )fill in "(?P<field>(?:[^"]|")*)" with "(?P<value>(?:[^"]|")*)"$/ default | Then /^print current URL$/ default | Then /^print last response$/ default | When /^(?:|I )select "(?P<option>(?:[^"]|")*)" from "(?P<select>(?:[^"]|")*)"$/ default | When /^(?:|I )check "(?P<option>(?:[^"]|")*)"$/ default | Then /^the "(?P<checkbox>(?:[^"]|")*)" checkbox should be checked$/ default | Then /^(?:|I )should see "(?P<text>(?:[^"]|")*)" in the "(?P<element>[^"]*)" element$/ Algunas Step Definitions que nos ofrece gratis Mink vía MinkContext: $ ./bin/behat -dl Nota: Otros contextos interesantes: Behatch, StepThroughExtension, PageObjectExtension
  • 67. Visit "https://www.wikipedia.org" and click on "English" Navegando por Wikipedia I am redirected to "wiki/Main_Page"
  • 68. I search "behat computer" and click on "Behat (computer science)" Navegando por Wikipedia
  • 69. Save references into a text file Navegando por Wikipedia
  • 70. Feature: Scrap behat references from wikipedia In order get behat references As an anonymous user I visit wikipedia behat entry and scrap the references list @javascript Scenario: Scrap references Given I am on "https://www.wikipedia.org" #Given I go to homepage Then I should see "The Free Encyclopedia" When I follow "English" Then the url should match "wiki/Main_Page" And I should see "Welcome to Wikipedia," When I fill in "Search Wikipedia" with "behat computer" And I press "Search Wikipedia" And print current URL #Debug And I follow "Behat (computer science)" Then I should see "Behat is intended to aid communication between" And I save references in a local storage device#Sentencia a implementar Archivo .feature: features/wikipedia.scrapper.feature
  • 71. use BehatMinkExtensionContextRawMinkContext; class FeatureContext extends RawMinkContext implements Context, SnippetAcceptingContext /** * @Given /^I save references in a local storage device$/ */ public function iSaveReferencesInALocalStorageDevice () { … } FeatureContext.php Requerido para obtener una Session de Mink
  • 72. /** @Given /^I save references in a local storage device$/ */ public function iSaveReferencesInALocalStorageDevice () { ... } Step Definition propio Método que guarda las preferencias. Paso a paso
  • 73. /** @Given /^I save references in a local storage device$/ */ public function iSaveReferencesInALocalStorageDevice () { $page = $this->getSession()->getPage(); ... } Obtener el objeto Page Obtener el objeto Session (pensar en una pestaña del navegador) Método que guarda las preferencias. Paso a paso
  • 74. /** @Given /^I save references in a local storage device$/ */ public function iSaveReferencesInALocalStorageDevice () { $page = $this->getSession()->getPage(); $content = $page->find('named', array('id', 'mw-content-text' )); } named Selector buscar por id Método que guarda las preferencias. Paso a paso
  • 75. /** @Given /^I save references in a local storage device$/ */ public function iSaveReferencesInALocalStorageDevice () { ... $references = $content->find('css', '.references'); $items = $references->findAll('css', 'li'); } Selectores CSS ¡Atención con el punto! find vs findAll Método que guarda las preferencias. Paso a paso
  • 76. /** @Given /^I save references in a local storage device$/ */ public function iSaveReferencesInALocalStorageDevice () { ... $links = array(); foreach ($items as $item) { $linkContainer = $item->find('xpath', '//span[@class="reference-text"]' ); $links[] = $linkContainer ->find('xpath', '//a/@href')->getText(); } } Selectores xpath obtener sólo el valor del enlace Método que guarda las preferencias. Paso a paso
  • 77. /** @Given /^I save references in a local storage device$/ */ public function iSaveReferencesInALocalStorageDevice () { ... file_put_contents ('scrapped_references.txt' , join(PHP_EOL, $links)); } Guardar el archivo en disco Método que guarda las preferencias. Paso a paso
  • 78. /** @Given /^I save references in a local storage device$/ */ public function iSaveReferencesInALocalStorageDevice () { $page = $this->getSession()->getPage(); $content = $page->find('named', array('id', 'mw-content-text' )); $references = $content->find('css', '.references'); $items = $references->findAll('css', 'li'); $links = array(); foreach ($items as $item) { $linkContainer = $item->find('xpath', '//span[@class="reference-text"]' ); $links[] = $linkContainer ->find('xpath', '//a/@href')->getText(); } file_put_contents ('scrapped_references.txt' , join(PHP_EOL, $links)); } 2.- Css Selectors 3.- Xpath Selectors 1.- Named Selector Método que guarda las preferencias. Paso a paso
  • 79. : implementar la misma solución con menor código Vamos a Refactorizar
  • 80. /** @Given /^I save references in a local storage device again$/ */ public function iSaveReferencesInALocalStorageDeviceAgain () { $closure = function($item) { return $item->getText(); }; // anonymous function $xpath = '//span[@class="reference-text"]/a/@href'; $links = array_map($closure, $this->findAll('xpath', $xpath)); file_put_contents ('scrapped_references_again.txt' , join(PHP_EOL, $links)); } public function __call($method, $parameters) { $page = $this->getSession()->getPage(); if (method_exists($page, $method)) { return call_user_func_array (array($page, $method), $parameters); } } Magic Call Sólo un selector xpath Método que guarda las preferencias. Solución corta Closure vs Lambda: https://www.ibm.com/developerworks/library/os-php-5.3new2/os-php-5.3new2-pdf.pdf
  • 82. bdd# ./bin/behat Feature: Scrap behat references from wikipedia ... Scenario: Scrap References # features/wikipedia.scrapper.feature:6 Given I am on " https://www.wikipedia.org" # BehatMinkExtensionContextMinkContext::visit() Then I should see " The Free Encyclopedia" # Behat...MinkContext::assertPageContainsText() When I follow " English" # Behat...MinkContext::clickLink() Then the url should match "wiki/Main_Page" # Behat...MinkContext::assertUrlRegExp() And I should see " Welcome to Wikipedia," # Behat...MinkContext::assertPageContainsText() When I fill in " Search Wikipedia" with "behat computer" # Behat...MinkContext::fillField() And I press " Search Wikipedia" # Behat...MinkContext::pressButton() And I follow " Behat (computer science)" # Behat...MinkContext::clickLink() Then I should see " Behat is intended to aid communication between developers, clients and other stakeholders during a..." # Behat...MinkContext::assertPageContainsText() And I save references in a local storage device # FeatureContext::iSaveReferencesInALocalStorageDevice() 1 scenario (1 passed) 10 steps (10 passed) 0m4.15s (15.36Mb)
  • 84. Echando una mano a Mink El flujo de ejecución de Behat está basado en eventos Behat provee 8 Hooks de gran ayuda. Principio DRY Los eventos se “mapean” mediante anotaciones Las anotaciones simplifican la gestión de Datafixtures Behat ofrece tags predefinidos (@javascript) y admite tags personalizados
  • 86. 1) Java JRE 2) Firefox, Chrome y/o otros drivers. Ver sección Third Party Drivers, Bindings, and Plugins at http://www.seleniumhq.org/download) 3) Selenium Standalone Server (http://www.seleniumhq.org/) 4) xvfb (X Virtual Frame Buffer). Permite crear una “gráfica virtual” en memoria. 5) Servidor web integrado por PHP (bin/console server:run) o un Servidor web con urlRewrite (Apache/nginx) y host debidamente configurado. Imprescindibles para ejecutar los tests: Nota: Firefox v.46 con selenium-server-standalone-2.53.1.jar funciona sin problemas
  • 87. En resumen: $ ./bin/behat --config ./app/config/behat.yml $ ./bin/console server:start $ java -jar ./bin/selenium-server-standalone-2.53.1.jar (see ./scripts/start-selenium.sh) $ sudo Xvfb :10 -ac Y finalmente: Imprescindibles para ejecutar los tests:
  • 88. Caso de Uso www.takeachef.com
  • 89. Caso de Uso www.takeachef.com I follow “Empezar” Existe otro “EMPEZAR” más abajo, se actuará sobre el primero que encuentre
  • 90. I follow “EMPEZAR” Internamente en findAll, dentro de Element.php se monta el siguiente xpath: //html/.//a[./@href][((./@id = 'EMPEZAR' or normalize-space(string(.)) = 'EMPEZAR' or ./@title = 'EMPEZAR' or ./@rel = 'EMPEZAR') or .//img[./@alt = 'EMPEZAR'])] | //html/.//*[translate(./@role,'ABCDEFGHIJKLMNOPQRSTUVWX YZ', 'abcdefghijklmnopqrstuvwxyz') = 'link'][((./@id = 'EMPEZAR' or ./@value = 'EMPEZAR') or ./@title = 'EMPEZAR' or normalize-space(string(.)) = 'EMPEZAR')] Caso de Uso
  • 91. Caso de Uso El driver que utilizamos en Mink es Selenium2 Éste a su vez interactúa con el driver de Firefox. Utilizaremos la anotación @javascript ya que el asistente sólo funciona con Javascript En Selenium Server Standalone Server 3.* el driver de Firefox a utilizar es Gecko
  • 92. Caso de Uso I should see “Encuentra tu Chef” I should see “ENCUENTRA TU CHEF” El tratamiento interno que hace Mink no siempre es el mismo. En este caso MinkContext llama al método de pagetTextContains el cual busca el texto mediante una expresión regular preg_match
  • 93. Caso de Uso I click “Continuar” Debido a un efecto delay en css: - Hay un hook en BeforeStep, que espera a que el contenedor esté del todo visible, utiliza función spins (alternativa: wait) - Hay creado 1 Step Definition propio para que busque el texto sobre el contenedor que esté activo y visible
  • 94. Para interacciones donde la respuesta no es inmediata Mink ofrece el método wait $this->getSession()->wait($seconds); No se considera una buena práctica la espera de un número determinado de segundos
  • 95. Pasar una evaluación Javascript es mucho mejor La comprobación se realiza cada 100 ms hasta un tiempo máximo expresamente definido // wait for n milliseconds until JS expression becomes true: $session->wait( 5000, "$('.suggestions-results').children().length" ); Espera a que la expresión javascript retorne verdadero hasta 5 segundos
  • 96. public function spins($closure, $seconds = 5, $fraction = 4) { $max = $seconds * $fraction; $i = 1; while ($i++ <= $max) { if ($closure($this)) { return true; } $this->getSession()->wait(1000 / $fraction); } $backtrace = debug_backtrace(); throw new Exception( sprintf("Timeout thrown by %s::%s()n%s, line %s" , $backtrace[0]['class'], $backtrace[0]['function'], $backtrace[0]['file'], $backtrace[0]['line'] ) ); } Timeout 5s por defecto Fracción de segundo En casos más complejos o por claridad de código. Función “propia” spins:
  • 97. Caso de Uso I fill in the address “Castellón” En este caso: - Hay creado 1 Step Definition propio para gestionar las direcciones que ofrece la Api de GoogleMaps. - También se contempla la función Spins ya que la carga de datos del desplegable es asíncrona y requiere un tiempo indeterminado
  • 98. Caso de Uso I click on “2 personas” I click on “13+ personas desde 35€” fallará ya que el texto está incluido en 2 elementos distintos
  • 99. Caso de Uso I click on “Quiero dejarme” I click on “wizard.preferences.surprise” No hace falta escribir todo el texto “Quiero dejarme sorprender” aunque es aconsejable No usar nunca la key de traducciones e internamente llamar al servicio translate o similar del framework utilizado, puede dar falsos positivos
  • 100. Caso de Uso I click on “Enviar” Finalizamos el proceso Aparecerá un loader, en este caso no hace falta utilizar la función spins ya que no utilizamos ajax, aunque lo pueda parecer. Mink se encarga de esperar a que se cargue la página correspondiente al enlace clicado.
  • 101. Caso de Uso I should see “¡Nuestros chefs ya están cocinando tu menú! Creamos un Step Definition propio y comprobamos que en base de datos se guardan los datos que hemos introducido en el test correctamente: - Solicitud con los datos del test - Creación de usuario - Envío de e-mails de confirmación - Derivación a Chefs (dados de alta anteriormente mediante DataFixtures) Práctica discutible, en ocasiones vale la pena ser prácticos
  • 102.