Вы находитесь на странице: 1из 11

CUCUMBER

INSTALACIN CONFIGURACIN
- Instalar consola coloreada. Ansicon.

http://www.agileforall.com/2011/08/getting-started-with-ruby-cucumber-and-capybara-on-windows/

- Descargar e instalar Ruby http://rubyinstaller.org/ Hay que marcar la casilla Add Ruby executables to
your PATH. Para estar seguros de que Ruby fue instalado correctamente, abre la lnea de comandos y
escribe ruby v, y debera aparecer la versin de Ruby instalada.
- Descargar e instalar Ruby Development Kit: https://github.com/oneclick/rubyinstaller/wiki/Development-Kit
- Esto es necesario para que se puedan instalar las gems de Ruby sin problemas en Windows. Una gem es
una biblioteca de Ruby.
- A continuacin, se ejecuta el .exe y se guarda en una carpeta del sistema.
- Desde la consola de Windows es necesario posicionarse en esa capeta y ejecutar ruby dk.rb init para
generar el fichero config.yml, despus ejecutar ruby dk.rb install para instalarlo.
- Para estar seguros de que las gems de Ruby fueron instaladas correctamente, escribe en la lnea de
comandos gem v, y debera aparecer la versin de las gems instalada.
- Adems es necesario ejecutar en la consola gem install json --platform=ruby y JSON debera estar instalado
correctamente, por lo que debera mostrar with native extensions. A continuacin, ejecutar ruby -
rubygems -e "require 'json'; puts JSON.load('[42]').inspect" para confirmar que la gem de JSON est
funcionando correctamente.
- Instalar cucumber: gem install Cucumber y una vez instalado, Cucumber help para confirmar que se
instal correctamente.

Caractersticas feature
En Cucumber, las pruebas estn agrupadas en caractersticas (en ingls features). Se denomina as porque en
ellas se describen las caractersticas del programa o sistema.

Cucumber sin argumentos, coge como directorio por defecto a uno llamado features y como no lo
encuentra, Cucumber avisa. Para solucionarlo, se debe crear dentro de la carpeta creada(la del directorio actual de
trabajo), un directorio llamado features.

Para crear una prueba, se va a crear un documento con la extensin .feature dentro del directorio features,
de la forma nombrePrueba.feature. La estructura de un fichero.feature bsica es:

Caracterstica: descripcin de la prueba

Para lograr un beneficio


Como rol
Quiero realizar una funcionalidad
Escenario: descripcin del caso de prueba
Dado un contexto inicial
Cuando ocurre un evento
Entonces asegurar que se obtiene

Se puede ver que Cucumber utiliza siempre las mismas palabras claves: Caracterstica (Feature), Escenario
(Scenario), Dado (Given), Cuando (When) y Entonces (Then). Estas palabras son la estructura y todo lo dems es
la documentacin.

Background Antecedentes

Una seccin background en un fichero .feature se utiliza para especificar un conjunto de casos de prueba que son
comunes para todos los escenarios del fichero. Las ventajas que tiene esto son evidentes:
- Si necesitas cambiar algo en el caso de prueba, solo es necesario cambiarlo una vez, y no por cada vez que lo
hubieras puesto.
- Cuando leas cada escenario te podrs centrar en lo principal, en lo que identifica a ese escenari o.

Solo se puede utilizar una seccin background en cada archivo feature, y debe aparecer antes de las palabras
claves Scenario o Scenario Outline.

Tablas de datos
Algunos casos de prueba necesitan describir datos que no son fciles de incluir en una lnea Given, When o Then.
Para ello, Gherkin permite incluir estos datos en tablas debajo de las declaraciones de los casos de prueba.

La tabla empieza inmediatamente despus del caso de prueba y los datos se separan con el carcter |. Se p uede
alinear los | usando espacios en blanco para hacer que la tabla se vea organizada, aunque a Cucumber no le
importa como lo hagas.

Convertir la tabla en un array

La tabla que se tena en el ejemplo anterior, tambin se puede ver como un array con dos dimensiones. Si se quiere
manipular esta tabla, ser ms til si se convierte en un array, de forma que utilizando el lenguaje de
programacin que se desee, se pueda tener una instancia con los datos de la tabla en forma de array. El
mtodo raw permite hacer esta conversin.

Scenario outline Esquema del escenario

A veces, se tienen muchos escenarios que siguen exactamente el mismo patrn de casos de prueba, cambiando solo
algunos valores o la salida.

Tantas repeticiones no ayudan a que el caso de prueba sea fcil de leer y puede ocasionar multitud de problemas,
como los que tiene el copy-paste, que no ayudar a tener unas pruebas de calidad. Cucumber permite usar
el scenario outline con el que se especifica primero el patrn del caso de prueba y despus los valores que
puede tener

Steps casos de prueba

Para crear los casos de prueba, primero se debe crear una carpeta llamada step_definitions dentro de la
carpeta features que se haba creado anteriormente. Es necesario que se llame de esa forma porque
Cucumber buscar de forma automtica los casos de prueba en la carpeta que encuentre llamada
step_definitions.

Para crear un caso de prueba, en esa carpeta se debe cr ear un archivo con extensin .rb.

En el archivo, se copiar el ejemplo del caso de prueba que haba mostrado en pantalla Cucumber. Es decir
las definiciones de los casos de prueba sin implementar.

Al ejecutar Cucumber (ver Ilustracin 6 Ejecutar Cucumber con las definiciones de caso de prueba sin
implementar) el escenario ha cambiado de undefined a pending. Esto significa que Cucumber ha ejecutado el
primer caso de prueba, pero como an no est implementado, lo marca como pendiente.
Adems, Cucumber ha cambiado los 3 steps (3 undefined) a 3 steps (2 skipped, 1 pending). Para entender esto,
hay que tener en cuenta que Cucumber cuando ejecuta un escenario, ejecuta los casos de prueba y si alguno
de ellos da fallo interrumpe la ejecucin y los siguientes los omite y se los salta.

Cada caracterstica contiene uno o ms escenarios. Cada escenario es un ejemplo concreto de cmo el sistema
debera comportarse en una situacin particular. Todos los escenariosexpresan el comportamiento de una
caracterstica.
Cuando Cucumber ejecuta un escenario, si el sistema se comporta como se ha descrito en l, se dice que el
escenario se pasa. Si no ocurre, ser fallido.
Cada vez que se aada un nuevo escenario a Cucumber y este lo marque como pasado, se habr aadido
alguna nueva funcionalidad al sistema.
Se debe tener en cuenta que cada escenario debe poder ser ejecutado de forma independiente de cualquier
otro escenario.
Para realizar un escenario se siguen tres pasos: se empieza indicando el contexto, se describe la accin y
finalmente se comprueba que la salida fue la que se esperaba, Given, When y Then .

Se puede diferenciar entre un caso de prueba (donde se explica lo que hace en un lenguaje que entienden
todos, son los archivos .feature) y la definicin de un caso de prueba (donde se implementa la prueba y se
ubican dentro de la carpeta step_definitions).

Cada escenario en Gherkin contiene una serie de casos de prueba escritos en un lenguaje que entienden todos.
Estos tambin forman la documentacin del sistema y necesitan la definicin de los caso de prueba para
decir a Cucumber qu es lo que tiene que hacer.

Capturar argumentos

Alternacin

Tambin se puede indicar que el valor puede oscilar entre varios, para ello se utiliza la alternacin. Con ella
se puede expresar diferentes opciones separadas por el carcter | como se indica:

Given /tengo (100|200) euros en mi cuenta/ do |cantidad|


# cdigo
end

La definicin del caso de prueba coger del caso de prueba uno de esos dos valores (100 o 200), y lo guardar en
el argumento cantidad.

El punto

Si por el contrario se quiere que la definicin del caso de prueba capture cualquier valor que se le pase, se utiliza el
punto:

Given /tengo () euros en mi cuenta/ do |cantidad|


# cdigo
end

Pero esto tiene el problema de que coge cualquier carcter, por lo que podra coger letras por ejemplo en vez de
nmeros. Adems, en el ejemplo que se puso siempre va a buscar 3 caracteres (ya que existen tres puntos, si
hubiera dos puntos buscara dos)

Modificador *

Para indicar que un carcter puede estar cualquier nmero de veces se utiliza el modificador *. Por lo que,
centrndonos en el ejemplo anterior, se podra utilizarlo para indicar que el valor de la cuenta puede ser de
cualquier longitud

Given /tengo (.*) euros en mi cuenta/ do |cantidad|


# cdigo
end
Clases de caracteres

Las clases de caracteres sirven para poner una expresin regular que indique un rango de caracteres. Se utilizan
poniendo todos los caracteres que se acepten entre corchetes:

Given /tengo ([0123456789]*) euros en mi cuenta/ do |cantidad|


# cdigo
end

Tambin se puede representar si se tiene un rango continuo de caracteres: ([0-9]*)

De esta forma se restringe los caracteres que pueda aceptar a solo nmeros y con el modificador * se acepta
que sea de cualquier longitud.

Clases de caracteres abreviados

Para patrones comunes de caracteres como [0-9], se pueden utilizar abreviaciones, los ms representativos son:

\d representa dgitos o [0-9]

\w representa guiones bajos, letras y dgitos pero no guiones [A-Za-z0-9_]

\s representa espacios en blanco (ya sea un espacio, tabulador o salto de lnea) [ \t\n]

El modificador * no es el nico modificador de repeticin y adems, cuando se utiliza sin pasarle nada, no da error y
no le pasa nada al argumento:

Sin embargo, el modificador + tiene como restriccin que haya al menos uno

Modificador ?

El modificador ? modifica el carcter que lo precede especificando si se puede repetir cero o una vez. Es
especialmente til para los plurales, ya que si lo utilizas antes de una s puedes indicar que puede estar o no

Por ejemplo:

Given tengo 1 euro en mi cuenta


Given tengo 100 euros en mi cuenta

La definicin del caso de prueba para ambos casos de prueba seria la misma, donde se indica con la ? que la s de
euros puede aparecer o no:

Given /tengo (\d+) euros? en mi cuenta/ do |cantidad|


# codigo
end

Carcter ?:

Si se aade el carcter ?: indica que no es un argumento:

When /yo (?:visto|voy a) la pagina principa/

Anclajes

^: indica el principio de la expresin regular

$: indica el final de la expresin regular


PASOS PARA REALIZAR UNA PRUEBA
Creamos una carpeta
Nos posicionamos en ella
Dentro de ella creamos la carpeta feature y dentro de esta la carpeta step_definitions
Debemos crear tambin en la carpeta feature una carpeta support con un fichero env.rb con el contenido:
require 'rspec'
Si lanzamos en este momento cucumber (escribiendo en la lnea de comandos cucumber) obtenemos:
0 scenarios
0 steps
0m0.000s

Ahora creamos un archivo .feature dentro de la carpeta step_definitions


Definimos el feature y el escenario:
Feature: sacar dinero de una cuenta
Para sacar dinero
Como cliente del banco
Quiero poder sacar dinero
Scenario: retirar dinero de una cuenta
Given tengo 100 euros en mi cuenta
When retiro 20 euros
Then 20 euros deberan ser proporcionados
Si ahora pasamos cucumber obtenemos:
Feature: sacar dinero de una cuenta
Para sacar dinero
Como cliente del banco
Quiero poder sacar dinero

Scenario: retirar dinero de una cuenta # features/step_definitions/retirar.feature:5


Given tengo 100 euros en mi cuenta # features/step_definitions/retirar.feature:6
When retiro 20 euros # features/step_definitions/retirar.feature:7
Then 20 euros deberan ser propor cionados # features/step_definitions/retirar.feature:8

1 scenario (1 undefined)
3 steps (3 undefined)
0m0.750s

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

Given(/^tengo (\d+) euros en mi cuenta$/) do |arg1|


pending # Write code here that turns the phrase above into concrete actions
end

When(/^retiro (\d+) euros$/) do |arg1|


pending # Write code here that turns the phrase above into concrete actions
end

Then(/^(\d+) euros deberan ser proporcionados$/) do |arg1|


pending # Write code here that turns the phrase above into concrete actions
end
Ahora copiamos y pegamos los step_definitions en un archivo .rb
Pasamos cucumber y obtenemos:
Feature: sacar dinero de una cuenta
Para sacar dinero
Como cliente del banco
Quiero poder sacar dinero

Scenario: retirar dinero de una cuenta # features/step_definitions/retirar.feature:5


Given tengo 100 euros en mi cuenta # features/step_definitions/step_retirar.rb:1
TODO (Cucumber::Pending)
./features/step_definitions/step_retirar.rb:2:in `/^tengo (\d+) euros en mi cuenta$/'
features/step_definitions/retirar.feature:6:in `Given tengo 100 euros en mi cuenta'
When retiro 20 euros # features/step_definitions/step_retirar.rb:5
Then 20 euros deberan ser proporcionados # features/step_definitions/step_retirar.rb:9

1 scenario (1 pending)
3 steps (2 skipped, 1 pending)
0m0.062s

Ahora debemos implementar los steps. Para ello tenemos que modificar el archivo .rb donde hemos incluido
los step_definitions que copiamos de la consola.
Pero antes debemos implementar las clases y mtodos necesarios. Incluimos el siguiente cdigo en el
archivo .rb
class Cuenta
def initialize
end
def depositar(dinero)
@saldo = dinero
end
def saldo
@saldo
end
end
Implementamos tambin el primer step:
Given(/^tengo (\d+) euros? en mi cuenta$/) do |dinero|
dinero = dinero.to_i
mi_cuenta = Cuenta.new
mi_cuenta.depositar(dinero)
mi_cuenta.saldo.should eq(dinero),
"Se esperaba que el saldo fuera #{dinero} pero no fue as, el saldo es
#{mi_cuenta.saldo}"
end

Pasamos cucumber y obtenemos que el primer step lo ha pasado:


Feature: sacar dinero de una cuenta
Para sacar dinero
Como cliente del banco
Quiero poder sacar dinero

Scenario: retirar dinero de una cuenta # features/step_definitions/retirar.feature:5


Given tengo 100 euros en mi cuenta # features/step_definitions/step_retirar.rb:1
When retiro 20 euros # features/step_definitions/step_retirar.rb:9
TODO (Cucumber::Pending)
./features/step_definitions/step_retirar.rb:10:in `/^retiro ( \d+) euros$/'
features/step_definitions/retirar.feature:7:in `When retiro 20 euros'
Then 20 euros deberan ser proporcionados #
features/step_definitions/step_retirar.rb:13

1 scenario (1 pending)
3 steps (1 skipped, 1 pending, 1 passed)
0m0.078s
Para implementar el segundo step necesitamos los mtodos y clases: (el modulo MiCuenta lo necsitamos
para poder acceder a la variable mi_cuenta
class Cajero module MiCuenta
def initialize def mi_cuenta
end @mi_cuenta ||=Cuenta.new
def retirar_de(cuenta, dinero) end
end end
end World(MiCuenta)
El segundo step quedara asi:
When(/^retiro (\d+) euros$/) do |arg1|
dinero = dinero.to_i
cajero = Cajero.new
cajero.retirar_de(mi_cuenta,dinero)
end
Y si pasamos cucumber obtenemos que se han pasado los dos primeros steps:
Feature: sacar dinero de una cuenta
Para sacar dinero
Como cliente del banco
Quiero poder sacar dinero

Scenario: retirar dinero de una cuenta # features/step_definitions/retirar.feature:5


Given tengo 100 euros en mi cuenta # features/step_definitions/step_retirar.rb:1
When retiro 20 euros # features/step_definitions/step_retirar.rb:9
Then 20 euros deberan ser proporcionados #
features/step_definitions/step_retirar.rb:15
TODO (Cucumber::Pending)
./features/step_definitions/step_retirar.rb:16:in `/^(\d+) euros deberan ser
proporcionados$/'
features/step_definitions/retirar.feature:8:in `Then 20 euros deberan ser
proporcionados'

1 scenario (1 pending)
3 steps (1 pending, 2 passed)
0m0.047s
Implementamos lo necesario para el tercer step asi como el step. Finalmente el archivo quedara as:
Given(/^tengo (\d+) euros? en mi cuenta$/) do |dinero|
dinero = dinero.to_i
mi_cuenta = Cuenta.new
mi_cuenta.depositar(dinero)
mi_cuenta.saldo.should eq(dinero),
"Se esperaba que el saldo fuera #{dinero} pero no fue as, el saldo es #{mi_cuenta.saldo}"
end

When(/^retiro (\d+) euros$/) do |dinero|


cajero.retirar_de(mi_cuenta,dinero)
end

Then(/^(\d+) euros deberan ser proporcionados$/) do |dinero|


salida_efectivo.contenido.should == dinero
end

class Cuenta
def initialize class Cajero
end def initialize(salida_efectivo)
def depositar(dinero) @Salida_efectivo = salida_efectivo
@saldo = dinero end
end def retirar_de(cuenta, dinero)
def saldo @Salida_efectivo.dispensar(dinero)
@saldo end
end end
end
class SalidaEfectivo module MiCuenta
def contenido def mi_cuenta
@contenido or raise("No hay nada!") @mi_cuenta ||=Cuenta.new
end end
def dispensar(dinero) def salida_efectivo
@contenido = dinero @salida_efectivo ||= SalidaEfectivo.new
end end
end def cajero
@cajero ||= Cajero.new(salida_efectivo)
end
end
World(MiCuenta)
Pasamos cucumber y obtenemos:
Feature: sacar dinero de una cuenta
Para sacar dinero
Como cliente del banco
Quiero poder sacar dinero

Scenario: retirar dinero de una cuenta # features/step_definitions/retirar.feature:5


Given tengo 100 euros en mi cuenta # features/step_definitions/step_retirar.rb:1
When retiro 20 euros # features/step_definitions/step_retirar.rb:9
Then 20 euros deberan ser proporcionados #
features/step_definitions/step_retirar.rb:13

1 scenario (1 passed)
3 steps (3 passed)
0m0.063s

Vamos a separar las clases en sus archivos correspondientes, cuenta.rb, cajero.rb y salida_efectivo.rb y asi
las eliminamos del fichero step_retirar.rb. Estos ficheros van a ir en una carpeta llamada lib en la raz del
proyecto. Debemos incluir: require File.join(File.dirname(__FILE__),'..','..','lib', 'nombrearchivo') en la
cabecera del fichero que use estas clases, es decir, donde se definen los steps.
Tambien los modulos que se aaden al contexto del World deben estar en un fichero dentro de la carpeta
support

Ahora modificamos el escenario para que valga para varios valores:


Feature: sacar dinero de una cuenta
Para sacar dinero
Como cliente del banco
Quiero poder sacar dinero
Scenario Outline: retirar dinero de una cuenta
Given tengo "<input>" euros en mi cuenta
When retiro "<output>" euros
Then "<output>" euros deberan ser proporcionados
Examples:
| input | output |
| 200 | 20 |
| 125 | 15 |
| 750 | 120 |

Y tenemos que modificar las cabeceras de los steps definitions:

Cambiamos:

(\d+)

Por:

"([^"]*)"

PARA QUE LO SIGUIENTE FUNCIONE HEMOS TENIDO QUE LOS @ en mi_cuenta EN TODOS LOS STEP DEFINITIONS
Ahora modificamos el escenario, tenemos que restar el dinero que ha quedado en la cuenta:
Feature: sacar dinero de una cuenta
Para sacar dinero
Como cliente del banco
Quiero poder sacar dinero
Scenario Outline: retirar dinero de una cuenta
Given tengo "<input>" euros en mi cuenta
When retiro "<output>" euros
Then "<output>" euros deberan ser proporcionados
And mi cuenta debera tener "<output2>"
Examples:
| input | output | output2 |
| 200 | 20 | 180 |
| 125 | 15 | 110 |
| 750 | 120 | 630 |
Si pasamos cucumber:
Feature: sacar dinero de una cuenta
Para sacar dinero
Como cliente del banco
Quiero poder sacar dinero

Scenario Outline: retirar dinero de una cuenta # features/step_definitions/retirar.feature:5


Given tengo "<input>" euros en mi cuenta # features/step_definitions/retirar.feature:6
When retiro "<output>" euros # features/step_definitions/retirar.feature:7
Then "<output>" euros deberan ser proporcionados # features/step_definitions/retirar.feature:8
And mi cuenta debera tener "<output2>" # features/step_definitions/retirar.feature:9

Examples:
| input | output | output2 |
| 200 | 20 | 180 |
| 125 | 15 | 110 |
| 750 | 120 | 630 |
| 555 | 55 | 500 |

4 scenarios (4 undefined)
16 steps (4 undefined, 12 passed)
0m0.047s

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

Then(/^mi cuenta debera tener "([^"]*)"$/) do |arg1|


pending # Write code here that turns the phrase above into concrete actions
end
Incluimos la definicin del caso de prueba:
Then(/^(/^mi cuenta debera tener "([^"]*)"$/) do |dinero|
dinero = dinero.to_i
@mi_cuenta.saldo.should eq(dinero),
"Se esperaba que el saldo fuera #{dinero} pero no fue as, el saldo es
#{mi_cuenta.saldo}"
end
Y modificamos:
class Cajero class Cuenta
def initialize(salida_efectivo) def initialize(dinero)
@Salida_efectivo = @saldo = dinero.to_i
salida_efectivo end
end def saldo
@saldo
def retirar_de(mi_cuenta, dinero) end
dinero = dinero.to_i def saldo=(saldo)
mi_cuenta.cargar(dinero) @saldo = saldo
end
@Salida_efectivo.dispensar(dinero) def cargar(dinero)
end
end self.saldo = self.saldo.to_i -
dinero
end
end
Y obtenemos:
Feature: sacar dinero de una cuenta
Para sacar dinero
Como cliente del banco
Quiero poder sacar dinero

Scenario Outline: retirar dinero de una cuenta # features/step_definitions/retirar.feature:5


Given tengo "<input>" euros en mi cuenta # features/step_definitions/retirar.feature:6
When retiro "<output>" euros # features/step_definitions/retirar.feature:7
Then "<output>" euros deberan ser proporcionados # features/step_definitions/retirar.feature:8
And mi cuenta debera tener "<output2>" # features/step_definitions/retirar.feature:9

Examples:
| input | output | output2 |
| 200 | 20 | 180 |
| 125 | 15 | 110 |
| 750 | 120 | 630 |
| 555 | 55 | 500 |

4 scenarios (4 passed)
16 steps (16 passed)
0m0.063s
Resumen de los archivos:

world_extensions.rb
module MiCuenta
def mi_cuenta
@mi_cuenta ||=Cuenta.new(0)
end

def salida_efectivo
@salida_efectivo ||= SalidaEfectivo.new
end
def cajero
@cajero ||= Cajero.new(salida_efectivo)
end
end
World(MiCuenta)

step_retirar.rb
require File.join(File.dirname(__FILE__),'..','..','lib', 'cajero.rb')
require File.join(File.dirname(__FILE__),'..','..','lib', 'cuenta.rb')
require File.join(File.dirname(__FILE__),'..','..','lib', 'salida_efectivo.rb')
Given(/^tengo "([^"]*)" euros? en mi cuenta$/) do |dinero|
dinero = dinero.to_i
@mi_cuenta = Cuenta.new(dinero)
end

When(/^retiro "([^"]*)" euros$/) do |dinero|


dinero = dinero.to_i
cajero.retirar_de(@mi_cuenta,dinero)
end

Then(/^"([^"]*)" euros deberan ser proporcionados$/) do |dinero|


salida_efectivo.contenido.should == dinero.to_i
end

Then(/^mi cuenta debera tener "([^"]*)"$/) do |dinero|


dinero = dinero.to_i
@mi_cuenta.saldo.should eq(dinero),
"Se esperaba que el saldo fuera #{dinero} pero no fue as, el saldo es
#{mi_cuenta.saldo}"
end
cajero.rb
class Cajero
def initialize(salida_efectivo)
@Salida_efectivo = salida_efectivo
end

def retirar_de(mi_cuenta, dinero)


dinero = dinero.to_i
mi_cuenta.cargar(dinero)
@Salida_efectivo.dispensar(dinero)
end
end
cuenta.rb
class Cuenta
def initialize(dinero)
@saldo = dinero.to_i
end
def saldo
@saldo
end
def saldo=(saldo)
@saldo = saldo
end
def cargar(dinero)

self.saldo = self.saldo.to_i - dinero


end
end

salida_efectivo.rb
class SalidaEfectivo
def contenido
@contenido or raise("No hay nada!")
end
def dispensar(dinero)
@contenido = dinero
end
end

Вам также может понравиться