SlideShare ist ein Scribd-Unternehmen logo
1 von 66
Downloaden Sie, um offline zu lesen
Cucumber:
Expresando Comportamiento en Texto Plano



                     Raimond Garcia Gimenez
                     Fernando Garcia Samblas
Antecedentes
2002: Ward Cunningham's Framework for Integrated Test
 Especificaciones ejecutables desde Word, Excel, Wikis, etc.


       Febrero 2007: Dan North's RSpec Stories
Stories escritas en Ruby y http://dannorth.net/whats-in-a-story


   Octubre 2007: David Chelimsky: plain text support
          Escritas en inglés y separadas del código


        Agosto 2008: Aslak Hellesøy's Cucumber
             Internacionalización y mucho más...
given/when/then

Feature: <funcionalidad>
In order to <beneficio/valor/why?>
As a <rol>
I want to <feature>



 Scenario: <escenario>
  Given <contexto>
  [And <contexto>]
  When <evento>
  [And <evento>]
  Then <resultado>
  [And <contexto>]
  [But <contexto>]
given/when/then

Feature: <funcionalidad>
 In order to <beneficio/valor/why?>
 As a <rol>
 I want to <feature>



 Scenario: <escenario>
  Given <contexto>
  [And <contexto>]
  When <evento>
  [And <evento>]
  Then <resultado>
  [And <contexto>]
  [But <contexto>]


Ejemplo en breve...                   With GivenScenario!
Limitaciones de RSpec Stories
Limitaciones de RSpec Stories




  Niñoooooooossss..... a comer!!!!!!
Resumiendo...
    Entorno Crudo
•Sin herramienta para lanzar stories/scenarios
•Sin soporte rake
•Sin convenciones
•Forzosamente escritas en ingles
•Feedback limitado
•Hooks preparacion/finalizacion artesanales
Cucumber
Script
•   script/cucumber
Script
•   script/cucumber
•   cucumber (default profile en cucumber.yml)
Script
•   script/cucumber
•   cucumber (default profile en cucumber.yml)
•   cucumber features
Script
•   script/cucumber
•   cucumber (default profile en cucumber.yml)
•   cucumber features
•   cucumber features/admin*
Script
•   script/cucumber
•   cucumber (default profile en cucumber.yml)
•   cucumber features
•   cucumber features/admin*
•   cucumber features/hola.feature
Script
•   script/cucumber
•   cucumber (default profile en cucumber.yml)
•   cucumber features
•   cucumber features/admin*
•   cucumber features/hola.feature
•   cucumber features/hola.feature --line 10
Script
•   script/cucumber
•   cucumber (default profile en cucumber.yml)
•   cucumber features
•   cucumber features/admin*
•   cucumber features/hola.feature
•   cucumber features/hola.feature --line 10
•   cucumber --profile html_report
Script
•   script/cucumber
•   cucumber (default profile en cucumber.yml)
•   cucumber features
•   cucumber features/admin*
•   cucumber features/hola.feature
•   cucumber features/hola.feature --line 10
•   cucumber --profile html_report



                      --require
Script
•   script/cucumber
•   cucumber (default profile en cucumber.yml)
•   cucumber features
•   cucumber features/admin*
•   cucumber features/hola.feature
•   cucumber features/hola.feature --line 10
•   cucumber --profile html_report
              --format
                   --require
Script
 •   script/cucumber
 •   cucumber (default profile en cucumber.yml)
 •   cucumber features
 •   cucumber features/admin*
 •   cucumber features/hola.feature
 •   cucumber features/hola.feature --line 10
 •   cucumber --profile html_report
         --format
--out=FILE    --require
Script
 •   script/cucumber
 •   cucumber (default profile en cucumber.yml)
 •   cucumber features
 •   cucumber features/admin*
 •   cucumber features/hola.feature
 •   cucumber features/hola.feature --line 10
 •   cucumber --profile html_report
         --format
--out=FILE    --require
                                        --no-source
Script
 •   script/cucumber
 •   cucumber (default profile en cucumber.yml)
 •   cucumber features
 •   cucumber features/admin*
 •   cucumber features/hola.feature
 •   cucumber features/hola.feature --line 10
 •   cucumber --profile html_report
         --format      --dry-run

--out=FILE    --require
                         --no-source
Script
 •   script/cucumber
 •   cucumber (default profile en cucumber.yml)
 •   cucumber features
 •   cucumber features/admin*
 •   cucumber features/hola.feature
 •   cucumber features/hola.feature --line 10
 •   cucumber --profile html_report
         --format       --dry-run

--out=FILE     --require
                          --no-source
          --language
Tarea de Rake
Cucumber::Rake::Task.new(:features) do |t|
  t.cucumber_opts = quot;--format prettyquot;
end
Tarea de Rake
   Cucumber::Rake::Task.new(:features) do |t|
     t.cucumber_opts = quot;--format prettyquot;
   end




      attr_accessors:
        cucumber_opts
   step_pattern / step_list
feature_pattern / feature_list
       rcov / rcov_opts
          libs / binary
Feedback
  Fichero y linea del escenario...




Scenario: with change something changes                        # features/edition.feature:15
    Given authentication is disabled                           # features/steps/given_wiki.rb:6
    And I have a page called quot;readmequot; with quot;Thanks!quot;           # features/steps/given_wiki.rb:2
    When I visit /readme                                       # features/steps/when_interactions.rb:39
    And I follow quot;Editquot;                                        # features/steps/when_interactions.rb:11
    And I fill in quot;bodyquot; with quot;This is my changed wiki page!quot; # features/steps/when_interactions.rb:15
    And I press quot;sendquot;                                         # features/steps/when_interactions.rb:3
      can't convert Symbol into String (TypeError)
      /Library/Ruby/Gems/1.8/gems/activesupport-2.2.0/lib/active_support/inflector.rb:261:in `escape'
      ./features/steps/../../sinatra_wiki.rb:39
    Then I should see quot;readmequot;                                 # features/steps/then_results.rb:2
    And I should NOT see quot;Thanks!quot;                             # features/steps/then_results.rb:6
    And I should see quot;This is my changed wiki page!quot;           # features/steps/then_results.rb:2

49 steps passed
4 steps failed
11 steps skipped
Feedback
  Fichero y linea del escenario...            cucumber features/edition.feature --line 15




Scenario: with change something changes                        # features/edition.feature:15
    Given authentication is disabled                           # features/steps/given_wiki.rb:6
    And I have a page called quot;readmequot; with quot;Thanks!quot;           # features/steps/given_wiki.rb:2
    When I visit /readme                                       # features/steps/when_interactions.rb:39
    And I follow quot;Editquot;                                        # features/steps/when_interactions.rb:11
    And I fill in quot;bodyquot; with quot;This is my changed wiki page!quot; # features/steps/when_interactions.rb:15
    And I press quot;sendquot;                                         # features/steps/when_interactions.rb:3
      can't convert Symbol into String (TypeError)
      /Library/Ruby/Gems/1.8/gems/activesupport-2.2.0/lib/active_support/inflector.rb:261:in `escape'
      ./features/steps/../../sinatra_wiki.rb:39
    Then I should see quot;readmequot;                                 # features/steps/then_results.rb:2
    And I should NOT see quot;Thanks!quot;                             # features/steps/then_results.rb:6
    And I should see quot;This is my changed wiki page!quot;           # features/steps/then_results.rb:2

49 steps passed
4 steps failed
11 steps skipped
Feedback
  Fichero y linea del escenario...            cucumber features/edition.feature --line 15

  ... y del step con parametros subrayados                    When /^I visit (.+)$/ do |url|



Scenario: with change something changes                        # features/edition.feature:15
    Given authentication is disabled                           # features/steps/given_wiki.rb:6
    And I have a page called quot;readmequot; with quot;Thanks!quot;           # features/steps/given_wiki.rb:2
    When I visit /readme                                       # features/steps/when_interactions.rb:39
    And I follow quot;Editquot;                                        # features/steps/when_interactions.rb:11
    And I fill in quot;bodyquot; with quot;This is my changed wiki page!quot; # features/steps/when_interactions.rb:15
    And I press quot;sendquot;                                         # features/steps/when_interactions.rb:3
      can't convert Symbol into String (TypeError)
      /Library/Ruby/Gems/1.8/gems/activesupport-2.2.0/lib/active_support/inflector.rb:261:in `escape'
      ./features/steps/../../sinatra_wiki.rb:39
    Then I should see quot;readmequot;                                 # features/steps/then_results.rb:2
    And I should NOT see quot;Thanks!quot;                             # features/steps/then_results.rb:6
    And I should see quot;This is my changed wiki page!quot;           # features/steps/then_results.rb:2

49 steps passed
4 steps failed
11 steps skipped
Feedback
  Fichero y linea del escenario...            cucumber features/edition.feature --line 15

  ... y del step con parametros subrayados                      When /^I visit (.+)$/ do |url|
  Coloreado completo (casi, lo veremos mas adelante)

Scenario: with change something changes                         #   features/edition.feature:15
    Given authentication is disabled                            #   features/steps/given_wiki.rb:6
    And I have a page called quot;readmequot; with quot;Thanks!quot;            #   features/steps/given_wiki.rb:2
    When I visit /readme                                        #   features/steps/when_interactions.rb:39
    And I follow quot;Editquot;                                         #   features/steps/when_interactions.rb:11
    And I fill in quot;bodyquot; with quot;This is my changed wiki page!quot;   #   features/steps/when_interactions.rb:15
    And I press quot;sendquot;                                          #   features/steps/when_interactions.rb:3
    Then I should see quot;readmequot;                                  #   features/steps/then_results.rb:2
    And I should NOT see quot;Thanks!quot;                              #   features/steps/then_results.rb:6
    And I should see quot;This is my changed wiki page!quot;            #   features/steps/then_results.rb:2

49 steps passed
3 steps failed
11 steps skipped
1 step pending
Feedback
  Fichero y linea del escenario...            cucumber features/edition.feature --line 15

  ... y del step con parametros subrayados                      When /^I visit (.+)$/ do |url|
  Coloreado completo (casi, lo veremos mas adelante)
                                           y step snippets!
Scenario: with change something changes                         #   features/edition.feature:15
    Given authentication is disabled                            #   features/steps/given_wiki.rb:6
    And I have a page called quot;readmequot; with quot;Thanks!quot;            #   features/steps/given_wiki.rb:2
    When I visit /readme                                        #   features/steps/when_interactions.rb:39
    And I follow quot;Editquot;                                         #   features/steps/when_interactions.rb:11
    And I fill in quot;bodyquot; with quot;This is my changed wiki page!quot;   #   features/steps/when_interactions.rb:15
    And I press quot;sendquot;                                          #   features/steps/when_interactions.rb:3
    Then I should see quot;readmequot;                                  #   features/steps/then_results.rb:2
    And I should NOT see quot;Thanks!quot;                              #   features/steps/then_results.rb:6
    And I should see quot;This is my changed wiki page!quot;            #   features/steps/then_results.rb:2

49 steps passed
3 steps failed
11 steps skipped
1 step pending

You can use these snippets to implement pending steps:

Then /^I press “send”$/ do
end
Deteccion de
        Ambiguedades
    Given /Tres (.*) ciegos/ do |animal|
    Given /Tres gatos (.*)/ do |handicap|




Given /Tres (.+) (.+)/ do |animal, handicap|


         Te obliga a ser mas DRY
         Mejora la mantenibilidad
FIT Tables
Característica: saludo localizado
  Para entender el mensaje de bienvenida
  Como un usuario
  Quiero que me saluden en mi idioma

  Escenario: Locale del browser
    Dado que el locale de mi browser es 'es_ES'
    Cuando visito la home
    Entonces vere el texto 'Buenos Dias Salao!'

   More i18n Examples:
     | locale | page     | Saludo          |
     | es_CA ! home      | Bones Salat! |
     | en_US ! home      | Good Day Salty! |
FIT Steps
  Dado el usuario Raimond de BeBanjo con email voodoo@example.com
nacido en Mallorca en 1982
  Y el usuario Nando de TheCocktail con email nando@example.com nacido
en Madrid en 1973
  Y el usuario Wadus de BeTheWadus con email wadus@example.com nacido
en WadusLand en 1847
FIT Steps
  Dado el usuario Raimond de BeBanjo con email voodoo@example.com
nacido en Mallorca en 1982
  Y el usuario Nando de TheCocktail con email nando@example.com nacido
en Madrid en 1973
  Y el usuario Wadus de BeTheWadus con email wadus@example.com nacido
en WadusLand en 1847




 Dado que existen los siguientes usuarios
   | nombre |    empresa   |      correo-e        |   ciudad      |   ano    |
   | Raimond | BeBanjo     | voodoo@example.com   |   Mallorca    |   1982   |
   | Nando   | TheCocktail | nando@example.com    |   Madrid      |   1973   |
   | Wadus   | BeTheWadus | wadus@example.com     |   WadusLand   |   1847   |
FIT Steps
  Dado el usuario Raimond de BeBanjo con email voodoo@example.com
nacido en Mallorca en 1982
  Y el usuario Nando de TheCocktail con email nando@example.com nacido
en Madrid en 1973
  Y el usuario Wadus de BeTheWadus con email wadus@example.com nacido
en WadusLand en 1847




 Dado que existen los siguientes usuarios
   | nombre |    empresa   |      correo-e        |   ciudad      |   ano    |
   | Raimond | BeBanjo     | voodoo@example.com   |   Mallorca    |   1982   |
   | Nando   | TheCocktail | nando@example.com    |   Madrid      |   1973   |
   | Wadus   | BeTheWadus | wadus@example.com     |   WadusLand   |   1847   |




      Given /que existen los siguientes usuarios/ do |usuarios|
        #Array de hashes, del tipo {:nombre => ‘Wadus’, ....}
      end
Autotest

Flow:
•Ejecuta tus specs hasta que todos pasen
•Ejecuta tus escenarios fallidos hasta que pasen
•Despues ejecuta todos sus specs otra vez
•Y todos los features

Puesta en marcha:
$ sudo gem install ZenTest
$ AUTOFEATURE=true autospec
Perfiles
             RAILS_ROOT/cucumber.yml

default:     --language es features
html:        --language es --format html features
performance: --language es --format profile features
Perfiles
                           RAILS_ROOT/cucumber.yml

         default:     --language es features
         html:        --language es --format html features
         performance: --language es --format profile features


$ cucumber --profile performance
Profiling enabled.
................................................................



Top 10 average slowest steps with 5 slowest matches:
0.0048184 When /^I (try)?(?: to )?visit [quot;']?([^quot;']+)[quot;']?$/i # features/steps/when_interactions.rb:39
  0.0290940 When I visit /brand-new # features/creation.feature:8
  0.0038860 When I visit /brand-new # features/creation.feature:25
  0.0035640 When I visit the home # features/destruction.feature:9
  0.0018260 When I visit the home # features/home.feature:8
  0.0017800 When I visit the home # features/destruction.feature:28
0.0039920 When /^I press [quot;']?([^quot;']+)[quot;']?$/i # features/steps/when_interactions.rb:3
  0.0057240 And I press quot;sendquot; # features/creation.feature:10
  0.0043170 And I press quot;sendquot; # features/edition.feature:11
  0.0035290 And I press quot;sendquot; # features/creation.feature:27
  0.0023980 And I press quot;sendquot; # features/edition.feature:21
i18n
lib/cucumber/languages.yml


cucumber --language es

feature: Característica
scenario: Escenario
given_scenario: DadoElEscenario
given: Dado
when: Cuando
then: Entonces
and: Y
Ejemplo
features/atencion.feature
Característica: Mantener Atencion


 Para que todo el mundo use Cucumber
 Como desarollador agil
 Quiero mantener la atencion de la audiencia durante la ponencia

  Escenario: Presentando la ponencia de Cucumber
    Dado Que presentamos una propuesta para la Conferencia Rails 2008
    Y Que nos las aceptan
    Y Que mandamos nuestras fotos xuflas
    Y Que confirmamos nuestra asistencia
    Y Que logramos llegar a tiempo despues de pillarnos un pedo en la cena del jueves

  Escenario: Crisis Temporal
    DadoElEscenario: Presentando la ponencia de Cucumber
    Y Que la audiencia comienza a quedarse sopa
    Cuando pulsamos “CTRL + SHIFT + R”
    Entonces sale una foto de unas tetas curiosas
    Y la gente se pone muy contenta
    Y algunos se rien

  Escenario: Exito Total
    DadoElEscenario: Presentando la ponencia de Cucumber
    Y Que la audiencia comienze a excitarse
    Cuando pulsamos “CTRL + R”
    Entonces sale una foto de media teta intrigante
    Y la gente se pone pensativa
Declarative vs
 Imperative
Estilo Imperativo

Cuando voy a la pagina de registrarme
Y relleno el campo 'email' con 'wadus@wadusland.com'
Y relleno el campo 'nombre' con 'wadus'
Y relleno el campo 'ciudad' con 'WadusLand'
Y relleno el campo 'telefono' con '111-999-333'
Y pincho en el boton 'Registrarme!'
Entonces 'wadus@wadusland.com' recibira un email
Y tendra como 'asunto' 'Bienvenido a WadusLand.com'
Estilo Imperativo

Cuando voy a la pagina de registrarme
Y relleno el campo 'email' con 'wadus@wadusland.com'
Y relleno el campo 'nombre' con 'wadus'
Y relleno el campo 'ciudad' con 'WadusLand'
Y relleno el campo 'telefono' con '111-999-333'
Y pincho en el boton 'Registrarme!'
Entonces 'wadus@wadusland.com' recibira un email
Y tendra como 'asunto' 'Bienvenido a WadusLand.com'


•   En el estilo IMPERATIVO lo importante es, COMO se consigue el
    objectivo
Estilo Declarativo

Cuando un nuevo usuario se registra
Entonces recibira un email con el 'asunto' 'Bienvenido a WadusLand.com'
Estilo Declarativo

Cuando un nuevo usuario se registra
Entonces recibira un email con el 'asunto' 'Bienvenido a WadusLand.com'




  •   En el estilo DECLARATIVO, lo importante es el QUE es nuestro
      objetivo
Declarative vs
            Imperative
Cual usar? pues depende del caso.
Quien va a leer la historia? hombre de negocio o desarrollador?
Que quieres testear y resaltar en esa historia?
Arte?
Big Picture
Nuestro Picture
Selenium setup
               en The Cocktail
Servidor CruiseControl:
 Linux Debian con Selenium-1.1.14.gem (selenium-driver, cliente)
 Build Secuencial (lanza APP siempre en el puerto 3000)
Servidor de Selenium Remote Control:
 Instancia Xen con Windows XP (sin ruby instalado)
 java 1.6.0 & ant 1.7.0
 selenium-server-0.9.2
    > java -jar selenium-server.jar

   Resolvemos test.host y www.example.com hacia la IP CruiseControl
The Cocktail Build
task :cruise => :environment do
  ENV['SELENIUM_SERVER'] = quot;selenium-serverquot;
  ENV['SELENIUM_BROWSER'] = quot;*iexplore C:Archivos de programaMultipleIEsIE6iexplore.exequot;
  Rake::Task['features'].invoke
  Rake::Task['features_with_ajax'].invoke
end

Cucumber::Rake::Task.new(:features_with_ajax) do |t|
  t.cucumber_opts = quot;--profile ajaxquot;
  t.feature_pattern = quot;features/caracteristicas_ajax/**/*.featurequot;
  t.step_list = quot;features/step_definitions/support/selenium_env.rbquot;
end

Cucumber::Rake::Task.new(:features) do |t|
  t.cucumber_opts = quot;--profile webratquot;
  t.feature_pattern = quot;features/caracteristicas/**/*.featurequot;
  t.step_list = quot;features/step_definitions/support/webrat_env.rbquot;
end


                              selenium_env.rb
app_server_pid = fork do
  [STDOUT, STDERR].each {|f| f.reopen('/dev/null','w')}
  exec quot;script/server -e #{ENV['RAILS_ENV']} -p #{apport}quot;
end
$selenium_driver = Selenium::SeleniumDriver.new(selenium_server, 4444, browser, appurl, 15000)
$selenium_driver.start
at_exit do
  $selenium_driver.stop
  Process.kill(9, app_server_pid)
end
Selenium setup
            en Bebanjo

• Todo en el mismo Servidor (SliceHost)
  Ubuntu
  Cruise(git)
  gema Selenium-1.1.14
  Xterm (Firefox)
Bebanjo Build
task :cruise do
  sh quot;script/cucumber features --profile webratquot;
  with_servers do
    sh quot;script/cucumber features --profile seleniumquot;
  end
end

def with_servers
  xserver_pid = run_command(quot;startx -- `which Xvfb` :1 -screen 0 1024x768x24quot;)
  selenium_pid = run_command(quot;sh -c 'DISPLAY=:1 selenium'quot;)
  webserver_pid = run_command(quot;script/server -e test -p #{ENV['WEBSERVER_PORT'] || 3000}quot;)
  yield
ensure
  system(quot;killall xtermquot;)
  Process.kill(9, webserver_pid)
  require 'selenium'
  Selenium::SeleniumServer.new.stop
end

def run_command(cmd)
  fork do
    [STDOUT,STDERR].each {|f| f.reopen '/dev/null', 'w' }
    exec cmd
  end
end


Selenium::SeleniumDriver.new(
  quot;localhostquot;, 4444, quot;*chromequot;,     # selenium-server, puerto, browser
  quot;http://localhost:3000quot;, 15000)   # servidor de aplicacion, timeout
Selenium-Grid
                  >   ant   launch-hub
                  >   ant   -Dport=5555 -Denvironment=quot;IExplorer6quot; launch-remote-control
                  >   ant   -Dport=5556 -Denvironment=quot;Firefox3quot; launch-remote-control
                  >   ant   -Dport=5557 -Denvironment=quot;GChromequot; launch-remote-control




SELENIUM_BROWSERS = {
  :firefox      => 'SELENIUM_BROWSER=quot;Firefox3quot;',
  :googlechrome => 'RAILS_ENV=test_chrome SELENIUM_BROWSER=quot;GChromequot; SELENIUM_APPORT=3001',
  :iexplorer    => 'RAILS_ENV=test_iexplorer SELENIUM_BROWSER=quot;IExplorer6quot; SELENIUM_APPORT=3002'
}

task :features_in_selenium_grid do
 pids, failures_in = {}, []
 SELENIUM_BROWSERS.each do |key, hash|
   pid = fork { exec(hash[:env] + ' SELENIUM_SERVER=selenium-server cucumber --profile selenium') }
   pids[pid] = key
 end

 SELENIUM_BROWSERS.size.times do
    Process.wait
    failures_in << pids[$?.pid] if $?.exitstatus == 0
 end
 raise 'Features failure in ' + failures_in.join(' and ') unless failures_in.empty?
end
TestJour
$ mkdir testjour-working-dir
$ testjour slave:start

$ testjour list

  Testjour servers:

      wadus       available   wadus-computer.local.:182499

$ testjour run features
Ventajas
•   Acerca el lenguaje empleado por el cliente (o business)
•   Abre la spec a todos los miembros del equipo (cliente incluido)
•   Emerge el vocabulario de la app (comunicacion mas precisa)
•   Integración de toda la aplicación (JavaScript incluido)
•   Ausencia de quot;paginas huerfanasquot; (de forma centralizada)
Ventajas
•   Acerca el lenguaje empleado por el cliente (o business)
•   Abre la spec a todos los miembros del equipo (cliente incluido)
•   Emerge el vocabulario de la app (comunicacion mas precisa)
•   Integración de toda la aplicación (JavaScript incluido)
•   Ausencia de quot;paginas huerfanasquot; (de forma centralizada)

y ademas:
• VERDE (no es COBOL)
Inconvenientes

•   Una mismo paso se puede expresar de mil formas

•   lentos?

•   funcionalidades globales en el layout

•   cuando spec y cuando feature

•   pocas convenciones...
Inconvenientes

• lentos?
• funcionalidades globales en el layout
• cuando spec y cuando feature
• pocas convenciones...
• VERDE (no es COBOL)
Paranoias y Deseos
      Imaginemos que ya tenemos todas las step_definitions escritas.
             Cuando escribo una nueva feature... que hago?

                             la comiteo petando el build?
                               me creo un rama ad-hoc?
                          creo un archivo/directorio especial?
                                    presssssssssss?
                                 !BASTA DE NIAPAS!
Scenario: with change something changes                         #   features/edition.feature:15
    Given authentication is disabled                            #   features/steps/given_wiki.rb:6
    And I have a page called quot;readmequot; with quot;Thanks!quot;            #   features/steps/given_wiki.rb:2
    When I visit /readme                                        #   features/steps/when_interactions.rb:39
    And I follow quot;Editquot;                                         #   features/steps/when_interactions.rb:11
    And I fill in quot;bodyquot; with quot;This is my changed wiki page!quot;   #   features/steps/when_interactions.rb:15
    And I press quot;sendquot;                                          #   features/steps/when_interactions.rb:3
    Then I should see quot;readmequot;                                  #   features/steps/then_results.rb:2
    And I should NOT see quot;Thanks!quot;                              #   features/steps/then_results.rb:6
    And I should see quot;This is my changed wiki page!quot;            #   features/steps/then_results.rb:2

49 steps passed
3 steps failed
11 steps skipped
1 step TODO (step definition done but pending app implementation)
Paranoias y Deseos
•   Problema: tenemos features con ajax y sin ajax separadas en diferentes
    archivos relacionadas con la mism feature, lo queremos todo junto.

•   Solucion: profile por escenario (HTML / JavaScript)



•   Problema: Testear unobtrusive-javascript sin duplicar escenarios.

•   Solucion: ProfileGroup (unobtrusive = html profile + javascript profile)
    Ademas que en el step definition sepamos el contexto (profile!) en el
    que se esta/debe ejectuarse (http, javascript)



•   Problema: usar fit tables en un escenario con muchas variables,
    Solucion: no se conoce hasta ahora...
Tip para reutilizar steps
             pensando en resources                  <li class='evento'>
                                                        <p><h3>Descripcion</h3>
para testear este codigo html                              <span>Conferencia Ruby Euroko 2009</span>
                                                        </p>
                                                    </li>


                                                     <% content_tag_for :li, evento do %>
                                                       <p class=quot;descripcionquot;>
podemos usar el                                             <%= evento.descripcion %>
content_tag_for en las vistas                          </p>
                                                     <% end %>



 y este step re-usable para todos los resources

Then quot;he should see the text '$text' within the $resource '$resource_attribute'quot; do |text, resource, resource_attribute|
  response_body.should have_tag_with_child(quot;.#{resource}quot;, quot;*quot;, /#{resource_attribute}/) do
    with_tag(quot;*quot;, /#{text}/)
  end
end
Tips
•   /i case insensitive, mayusculas y minusculas, que mas da!
•   shouldify, not_shouldify
•   try_if_try, 40X response
    children = @resource.send(child_model.table_name)
    blog.posts
    child = @resource.send(child_model.name.downcase)
    blog.user
•   def unquote(text)
       text =~ /^['quot;](.*)['quot;]$/ ? $1 : text
      end
    end
    ‘edit article’, “edit article”, edit article
•   selenium -browserSessionReuse &
more tips
- Parentesis Grouping-only en RegExps: /(?:...)/

Por ejemplo:


      ...(?:(?:en|con) estado|como)?...
Cazaria:


Dado que la categoria BDD tiene 3 libros
Y que dichos libros estan publicados
o bien:
Y que dichos libros estan como publicados
Y que dichos libros estan en estado publicado
anti-dolores tip

•   si en un step utilizamos RegExp no podemos usar variables $

•   selenium setup for ie6

> java -jar selenium-server.jar -interactive
...
cmd=getNewBrowserSession&1=*iexplore&2=http://test.host:3000
(...y podemos cerrar el navegador que nos abre)
GRACIAS!
• Gracias a Mamuso por el casco para volver a casa
  en moto a las tantas
• Gracias a Macla por la foto de la ensalada
• Gracias a nuestros jefes por darnos el miercoles
  para terminar la ponencia
• Gracias a Vosotros por haber venido!
• Preguntas?
http://github.com/voodoorai2000/conferenciarails2008

Weitere ähnliche Inhalte

Ähnlich wie Cucumber: expresando comportamiento en texto plano

Descubriendo Ruby on Rails (Desarrollo Agil de Aplicaciones Web)
Descubriendo Ruby on Rails (Desarrollo Agil de Aplicaciones Web)Descubriendo Ruby on Rails (Desarrollo Agil de Aplicaciones Web)
Descubriendo Ruby on Rails (Desarrollo Agil de Aplicaciones Web)lenny
 
Descubriendo Ruby On Rails (Desarrollo Agil De Aplicaciones Web)
Descubriendo Ruby On Rails (Desarrollo Agil De Aplicaciones Web)Descubriendo Ruby On Rails (Desarrollo Agil De Aplicaciones Web)
Descubriendo Ruby On Rails (Desarrollo Agil De Aplicaciones Web)INSIGNIA4U
 
Meetup training Taller RoR
Meetup training Taller RoR Meetup training Taller RoR
Meetup training Taller RoR cdechauri
 
Buenas Prácticas de desarrollo en Ruby on Rails
Buenas Prácticas de desarrollo en Ruby on RailsBuenas Prácticas de desarrollo en Ruby on Rails
Buenas Prácticas de desarrollo en Ruby on RailsSergio Gil
 
Presentación Ruby on Rails en Softare Freedom Day 09 Buenos Aires
Presentación Ruby on Rails en Softare Freedom Day 09 Buenos AiresPresentación Ruby on Rails en Softare Freedom Day 09 Buenos Aires
Presentación Ruby on Rails en Softare Freedom Day 09 Buenos Airespeterpunk
 
Workflows On Rails
Workflows On RailsWorkflows On Rails
Workflows On RailsDiego Moreno
 
Las buenas prácticas oficiales para aplicaciones Symfony
Las buenas prácticas oficiales para aplicaciones SymfonyLas buenas prácticas oficiales para aplicaciones Symfony
Las buenas prácticas oficiales para aplicaciones Symfonysymfony_bcn
 
Ejemplos de herramientas case más utilizadas
Ejemplos de herramientas case más utilizadasEjemplos de herramientas case más utilizadas
Ejemplos de herramientas case más utilizadasKenny Cash
 
Un newbie conoce a Sinatra
Un newbie conoce a SinatraUn newbie conoce a Sinatra
Un newbie conoce a SinatraJano González
 
Taller de Introducción a Ruby on Rails (2ª parte)
Taller de Introducción a Ruby on Rails (2ª parte)Taller de Introducción a Ruby on Rails (2ª parte)
Taller de Introducción a Ruby on Rails (2ª parte)Diacode
 
La Caja de Herramientas del Desarrollador Moderno PHPConferenceAR
La Caja de Herramientas del Desarrollador Moderno PHPConferenceARLa Caja de Herramientas del Desarrollador Moderno PHPConferenceAR
La Caja de Herramientas del Desarrollador Moderno PHPConferenceARPablo Godel
 
Presentacion Ruby on Rails CTIC-Cusco2007
Presentacion Ruby on Rails CTIC-Cusco2007Presentacion Ruby on Rails CTIC-Cusco2007
Presentacion Ruby on Rails CTIC-Cusco2007JuancaPompilla
 
Reportes En J Developer Parte 1 Y 2
Reportes En J Developer   Parte 1 Y 2Reportes En J Developer   Parte 1 Y 2
Reportes En J Developer Parte 1 Y 2Steven Gomez
 

Ähnlich wie Cucumber: expresando comportamiento en texto plano (20)

Descubriendo Ruby on Rails (Desarrollo Agil de Aplicaciones Web)
Descubriendo Ruby on Rails (Desarrollo Agil de Aplicaciones Web)Descubriendo Ruby on Rails (Desarrollo Agil de Aplicaciones Web)
Descubriendo Ruby on Rails (Desarrollo Agil de Aplicaciones Web)
 
Descubriendo Ruby On Rails (Desarrollo Agil De Aplicaciones Web)
Descubriendo Ruby On Rails (Desarrollo Agil De Aplicaciones Web)Descubriendo Ruby On Rails (Desarrollo Agil De Aplicaciones Web)
Descubriendo Ruby On Rails (Desarrollo Agil De Aplicaciones Web)
 
Taller de Capistrano
Taller de CapistranoTaller de Capistrano
Taller de Capistrano
 
Meetup training Taller RoR
Meetup training Taller RoR Meetup training Taller RoR
Meetup training Taller RoR
 
Buenas Prácticas de desarrollo en Ruby on Rails
Buenas Prácticas de desarrollo en Ruby on RailsBuenas Prácticas de desarrollo en Ruby on Rails
Buenas Prácticas de desarrollo en Ruby on Rails
 
Plone en La Jornada
Plone en La JornadaPlone en La Jornada
Plone en La Jornada
 
Anatomia de Plone
Anatomia de PloneAnatomia de Plone
Anatomia de Plone
 
Presentación Ruby on Rails en Softare Freedom Day 09 Buenos Aires
Presentación Ruby on Rails en Softare Freedom Day 09 Buenos AiresPresentación Ruby on Rails en Softare Freedom Day 09 Buenos Aires
Presentación Ruby on Rails en Softare Freedom Day 09 Buenos Aires
 
Html5
Html5Html5
Html5
 
Workflows On Rails
Workflows On RailsWorkflows On Rails
Workflows On Rails
 
Las buenas prácticas oficiales para aplicaciones Symfony
Las buenas prácticas oficiales para aplicaciones SymfonyLas buenas prácticas oficiales para aplicaciones Symfony
Las buenas prácticas oficiales para aplicaciones Symfony
 
Ant Log4j
Ant Log4jAnt Log4j
Ant Log4j
 
Ejemplos de herramientas case más utilizadas
Ejemplos de herramientas case más utilizadasEjemplos de herramientas case más utilizadas
Ejemplos de herramientas case más utilizadas
 
Un newbie conoce a Sinatra
Un newbie conoce a SinatraUn newbie conoce a Sinatra
Un newbie conoce a Sinatra
 
Taller de Introducción a Ruby on Rails (2ª parte)
Taller de Introducción a Ruby on Rails (2ª parte)Taller de Introducción a Ruby on Rails (2ª parte)
Taller de Introducción a Ruby on Rails (2ª parte)
 
La Caja de Herramientas del Desarrollador Moderno PHPConferenceAR
La Caja de Herramientas del Desarrollador Moderno PHPConferenceARLa Caja de Herramientas del Desarrollador Moderno PHPConferenceAR
La Caja de Herramientas del Desarrollador Moderno PHPConferenceAR
 
BDD con Mink y Behat
BDD con Mink y BehatBDD con Mink y Behat
BDD con Mink y Behat
 
Primefaces
PrimefacesPrimefaces
Primefaces
 
Presentacion Ruby on Rails CTIC-Cusco2007
Presentacion Ruby on Rails CTIC-Cusco2007Presentacion Ruby on Rails CTIC-Cusco2007
Presentacion Ruby on Rails CTIC-Cusco2007
 
Reportes En J Developer Parte 1 Y 2
Reportes En J Developer   Parte 1 Y 2Reportes En J Developer   Parte 1 Y 2
Reportes En J Developer Parte 1 Y 2
 

Kürzlich hochgeladen

guía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan Josephguía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan JosephBRAYANJOSEPHPEREZGOM
 
International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)GDGSucre
 
Global Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft FabricGlobal Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft FabricKeyla Dolores Méndez
 
Desarrollo Web Moderno con Svelte 2024.pdf
Desarrollo Web Moderno con Svelte 2024.pdfDesarrollo Web Moderno con Svelte 2024.pdf
Desarrollo Web Moderno con Svelte 2024.pdfJulian Lamprea
 
pruebas unitarias unitarias en java con JUNIT
pruebas unitarias unitarias en java con JUNITpruebas unitarias unitarias en java con JUNIT
pruebas unitarias unitarias en java con JUNITMaricarmen Sánchez Ruiz
 
EPA-pdf resultado da prova presencial Uninove
EPA-pdf resultado da prova presencial UninoveEPA-pdf resultado da prova presencial Uninove
EPA-pdf resultado da prova presencial UninoveFagnerLisboa3
 
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...silviayucra2
 
Trabajo Mas Completo De Excel en clase tecnología
Trabajo Mas Completo De Excel en clase tecnologíaTrabajo Mas Completo De Excel en clase tecnología
Trabajo Mas Completo De Excel en clase tecnologíassuserf18419
 
Proyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptxProyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptx241521559
 
Presentación guía sencilla en Microsoft Excel.pptx
Presentación guía sencilla en Microsoft Excel.pptxPresentación guía sencilla en Microsoft Excel.pptx
Presentación guía sencilla en Microsoft Excel.pptxLolaBunny11
 

Kürzlich hochgeladen (10)

guía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan Josephguía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan Joseph
 
International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)
 
Global Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft FabricGlobal Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft Fabric
 
Desarrollo Web Moderno con Svelte 2024.pdf
Desarrollo Web Moderno con Svelte 2024.pdfDesarrollo Web Moderno con Svelte 2024.pdf
Desarrollo Web Moderno con Svelte 2024.pdf
 
pruebas unitarias unitarias en java con JUNIT
pruebas unitarias unitarias en java con JUNITpruebas unitarias unitarias en java con JUNIT
pruebas unitarias unitarias en java con JUNIT
 
EPA-pdf resultado da prova presencial Uninove
EPA-pdf resultado da prova presencial UninoveEPA-pdf resultado da prova presencial Uninove
EPA-pdf resultado da prova presencial Uninove
 
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
POWER POINT YUCRAElabore una PRESENTACIÓN CORTA sobre el video película: La C...
 
Trabajo Mas Completo De Excel en clase tecnología
Trabajo Mas Completo De Excel en clase tecnologíaTrabajo Mas Completo De Excel en clase tecnología
Trabajo Mas Completo De Excel en clase tecnología
 
Proyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptxProyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptx
 
Presentación guía sencilla en Microsoft Excel.pptx
Presentación guía sencilla en Microsoft Excel.pptxPresentación guía sencilla en Microsoft Excel.pptx
Presentación guía sencilla en Microsoft Excel.pptx
 

Cucumber: expresando comportamiento en texto plano

  • 1. Cucumber: Expresando Comportamiento en Texto Plano Raimond Garcia Gimenez Fernando Garcia Samblas
  • 2. Antecedentes 2002: Ward Cunningham's Framework for Integrated Test Especificaciones ejecutables desde Word, Excel, Wikis, etc. Febrero 2007: Dan North's RSpec Stories Stories escritas en Ruby y http://dannorth.net/whats-in-a-story Octubre 2007: David Chelimsky: plain text support Escritas en inglés y separadas del código Agosto 2008: Aslak Hellesøy's Cucumber Internacionalización y mucho más...
  • 3. given/when/then Feature: <funcionalidad> In order to <beneficio/valor/why?> As a <rol> I want to <feature> Scenario: <escenario> Given <contexto> [And <contexto>] When <evento> [And <evento>] Then <resultado> [And <contexto>] [But <contexto>]
  • 4. given/when/then Feature: <funcionalidad> In order to <beneficio/valor/why?> As a <rol> I want to <feature> Scenario: <escenario> Given <contexto> [And <contexto>] When <evento> [And <evento>] Then <resultado> [And <contexto>] [But <contexto>] Ejemplo en breve... With GivenScenario!
  • 6. Limitaciones de RSpec Stories Niñoooooooossss..... a comer!!!!!!
  • 7.
  • 8.
  • 9.
  • 10. Resumiendo... Entorno Crudo •Sin herramienta para lanzar stories/scenarios •Sin soporte rake •Sin convenciones •Forzosamente escritas en ingles •Feedback limitado •Hooks preparacion/finalizacion artesanales
  • 12. Script • script/cucumber
  • 13. Script • script/cucumber • cucumber (default profile en cucumber.yml)
  • 14. Script • script/cucumber • cucumber (default profile en cucumber.yml) • cucumber features
  • 15. Script • script/cucumber • cucumber (default profile en cucumber.yml) • cucumber features • cucumber features/admin*
  • 16. Script • script/cucumber • cucumber (default profile en cucumber.yml) • cucumber features • cucumber features/admin* • cucumber features/hola.feature
  • 17. Script • script/cucumber • cucumber (default profile en cucumber.yml) • cucumber features • cucumber features/admin* • cucumber features/hola.feature • cucumber features/hola.feature --line 10
  • 18. Script • script/cucumber • cucumber (default profile en cucumber.yml) • cucumber features • cucumber features/admin* • cucumber features/hola.feature • cucumber features/hola.feature --line 10 • cucumber --profile html_report
  • 19. Script • script/cucumber • cucumber (default profile en cucumber.yml) • cucumber features • cucumber features/admin* • cucumber features/hola.feature • cucumber features/hola.feature --line 10 • cucumber --profile html_report --require
  • 20. Script • script/cucumber • cucumber (default profile en cucumber.yml) • cucumber features • cucumber features/admin* • cucumber features/hola.feature • cucumber features/hola.feature --line 10 • cucumber --profile html_report --format --require
  • 21. Script • script/cucumber • cucumber (default profile en cucumber.yml) • cucumber features • cucumber features/admin* • cucumber features/hola.feature • cucumber features/hola.feature --line 10 • cucumber --profile html_report --format --out=FILE --require
  • 22. Script • script/cucumber • cucumber (default profile en cucumber.yml) • cucumber features • cucumber features/admin* • cucumber features/hola.feature • cucumber features/hola.feature --line 10 • cucumber --profile html_report --format --out=FILE --require --no-source
  • 23. Script • script/cucumber • cucumber (default profile en cucumber.yml) • cucumber features • cucumber features/admin* • cucumber features/hola.feature • cucumber features/hola.feature --line 10 • cucumber --profile html_report --format --dry-run --out=FILE --require --no-source
  • 24. Script • script/cucumber • cucumber (default profile en cucumber.yml) • cucumber features • cucumber features/admin* • cucumber features/hola.feature • cucumber features/hola.feature --line 10 • cucumber --profile html_report --format --dry-run --out=FILE --require --no-source --language
  • 25. Tarea de Rake Cucumber::Rake::Task.new(:features) do |t| t.cucumber_opts = quot;--format prettyquot; end
  • 26. Tarea de Rake Cucumber::Rake::Task.new(:features) do |t| t.cucumber_opts = quot;--format prettyquot; end attr_accessors: cucumber_opts step_pattern / step_list feature_pattern / feature_list rcov / rcov_opts libs / binary
  • 27. Feedback Fichero y linea del escenario... Scenario: with change something changes # features/edition.feature:15 Given authentication is disabled # features/steps/given_wiki.rb:6 And I have a page called quot;readmequot; with quot;Thanks!quot; # features/steps/given_wiki.rb:2 When I visit /readme # features/steps/when_interactions.rb:39 And I follow quot;Editquot; # features/steps/when_interactions.rb:11 And I fill in quot;bodyquot; with quot;This is my changed wiki page!quot; # features/steps/when_interactions.rb:15 And I press quot;sendquot; # features/steps/when_interactions.rb:3 can't convert Symbol into String (TypeError) /Library/Ruby/Gems/1.8/gems/activesupport-2.2.0/lib/active_support/inflector.rb:261:in `escape' ./features/steps/../../sinatra_wiki.rb:39 Then I should see quot;readmequot; # features/steps/then_results.rb:2 And I should NOT see quot;Thanks!quot; # features/steps/then_results.rb:6 And I should see quot;This is my changed wiki page!quot; # features/steps/then_results.rb:2 49 steps passed 4 steps failed 11 steps skipped
  • 28. Feedback Fichero y linea del escenario... cucumber features/edition.feature --line 15 Scenario: with change something changes # features/edition.feature:15 Given authentication is disabled # features/steps/given_wiki.rb:6 And I have a page called quot;readmequot; with quot;Thanks!quot; # features/steps/given_wiki.rb:2 When I visit /readme # features/steps/when_interactions.rb:39 And I follow quot;Editquot; # features/steps/when_interactions.rb:11 And I fill in quot;bodyquot; with quot;This is my changed wiki page!quot; # features/steps/when_interactions.rb:15 And I press quot;sendquot; # features/steps/when_interactions.rb:3 can't convert Symbol into String (TypeError) /Library/Ruby/Gems/1.8/gems/activesupport-2.2.0/lib/active_support/inflector.rb:261:in `escape' ./features/steps/../../sinatra_wiki.rb:39 Then I should see quot;readmequot; # features/steps/then_results.rb:2 And I should NOT see quot;Thanks!quot; # features/steps/then_results.rb:6 And I should see quot;This is my changed wiki page!quot; # features/steps/then_results.rb:2 49 steps passed 4 steps failed 11 steps skipped
  • 29. Feedback Fichero y linea del escenario... cucumber features/edition.feature --line 15 ... y del step con parametros subrayados When /^I visit (.+)$/ do |url| Scenario: with change something changes # features/edition.feature:15 Given authentication is disabled # features/steps/given_wiki.rb:6 And I have a page called quot;readmequot; with quot;Thanks!quot; # features/steps/given_wiki.rb:2 When I visit /readme # features/steps/when_interactions.rb:39 And I follow quot;Editquot; # features/steps/when_interactions.rb:11 And I fill in quot;bodyquot; with quot;This is my changed wiki page!quot; # features/steps/when_interactions.rb:15 And I press quot;sendquot; # features/steps/when_interactions.rb:3 can't convert Symbol into String (TypeError) /Library/Ruby/Gems/1.8/gems/activesupport-2.2.0/lib/active_support/inflector.rb:261:in `escape' ./features/steps/../../sinatra_wiki.rb:39 Then I should see quot;readmequot; # features/steps/then_results.rb:2 And I should NOT see quot;Thanks!quot; # features/steps/then_results.rb:6 And I should see quot;This is my changed wiki page!quot; # features/steps/then_results.rb:2 49 steps passed 4 steps failed 11 steps skipped
  • 30. Feedback Fichero y linea del escenario... cucumber features/edition.feature --line 15 ... y del step con parametros subrayados When /^I visit (.+)$/ do |url| Coloreado completo (casi, lo veremos mas adelante) Scenario: with change something changes # features/edition.feature:15 Given authentication is disabled # features/steps/given_wiki.rb:6 And I have a page called quot;readmequot; with quot;Thanks!quot; # features/steps/given_wiki.rb:2 When I visit /readme # features/steps/when_interactions.rb:39 And I follow quot;Editquot; # features/steps/when_interactions.rb:11 And I fill in quot;bodyquot; with quot;This is my changed wiki page!quot; # features/steps/when_interactions.rb:15 And I press quot;sendquot; # features/steps/when_interactions.rb:3 Then I should see quot;readmequot; # features/steps/then_results.rb:2 And I should NOT see quot;Thanks!quot; # features/steps/then_results.rb:6 And I should see quot;This is my changed wiki page!quot; # features/steps/then_results.rb:2 49 steps passed 3 steps failed 11 steps skipped 1 step pending
  • 31. Feedback Fichero y linea del escenario... cucumber features/edition.feature --line 15 ... y del step con parametros subrayados When /^I visit (.+)$/ do |url| Coloreado completo (casi, lo veremos mas adelante) y step snippets! Scenario: with change something changes # features/edition.feature:15 Given authentication is disabled # features/steps/given_wiki.rb:6 And I have a page called quot;readmequot; with quot;Thanks!quot; # features/steps/given_wiki.rb:2 When I visit /readme # features/steps/when_interactions.rb:39 And I follow quot;Editquot; # features/steps/when_interactions.rb:11 And I fill in quot;bodyquot; with quot;This is my changed wiki page!quot; # features/steps/when_interactions.rb:15 And I press quot;sendquot; # features/steps/when_interactions.rb:3 Then I should see quot;readmequot; # features/steps/then_results.rb:2 And I should NOT see quot;Thanks!quot; # features/steps/then_results.rb:6 And I should see quot;This is my changed wiki page!quot; # features/steps/then_results.rb:2 49 steps passed 3 steps failed 11 steps skipped 1 step pending You can use these snippets to implement pending steps: Then /^I press “send”$/ do end
  • 32. Deteccion de Ambiguedades Given /Tres (.*) ciegos/ do |animal| Given /Tres gatos (.*)/ do |handicap| Given /Tres (.+) (.+)/ do |animal, handicap| Te obliga a ser mas DRY Mejora la mantenibilidad
  • 33. FIT Tables Característica: saludo localizado Para entender el mensaje de bienvenida Como un usuario Quiero que me saluden en mi idioma Escenario: Locale del browser Dado que el locale de mi browser es 'es_ES' Cuando visito la home Entonces vere el texto 'Buenos Dias Salao!' More i18n Examples: | locale | page | Saludo | | es_CA ! home | Bones Salat! | | en_US ! home | Good Day Salty! |
  • 34. FIT Steps Dado el usuario Raimond de BeBanjo con email voodoo@example.com nacido en Mallorca en 1982 Y el usuario Nando de TheCocktail con email nando@example.com nacido en Madrid en 1973 Y el usuario Wadus de BeTheWadus con email wadus@example.com nacido en WadusLand en 1847
  • 35. FIT Steps Dado el usuario Raimond de BeBanjo con email voodoo@example.com nacido en Mallorca en 1982 Y el usuario Nando de TheCocktail con email nando@example.com nacido en Madrid en 1973 Y el usuario Wadus de BeTheWadus con email wadus@example.com nacido en WadusLand en 1847 Dado que existen los siguientes usuarios | nombre | empresa | correo-e | ciudad | ano | | Raimond | BeBanjo | voodoo@example.com | Mallorca | 1982 | | Nando | TheCocktail | nando@example.com | Madrid | 1973 | | Wadus | BeTheWadus | wadus@example.com | WadusLand | 1847 |
  • 36. FIT Steps Dado el usuario Raimond de BeBanjo con email voodoo@example.com nacido en Mallorca en 1982 Y el usuario Nando de TheCocktail con email nando@example.com nacido en Madrid en 1973 Y el usuario Wadus de BeTheWadus con email wadus@example.com nacido en WadusLand en 1847 Dado que existen los siguientes usuarios | nombre | empresa | correo-e | ciudad | ano | | Raimond | BeBanjo | voodoo@example.com | Mallorca | 1982 | | Nando | TheCocktail | nando@example.com | Madrid | 1973 | | Wadus | BeTheWadus | wadus@example.com | WadusLand | 1847 | Given /que existen los siguientes usuarios/ do |usuarios| #Array de hashes, del tipo {:nombre => ‘Wadus’, ....} end
  • 37. Autotest Flow: •Ejecuta tus specs hasta que todos pasen •Ejecuta tus escenarios fallidos hasta que pasen •Despues ejecuta todos sus specs otra vez •Y todos los features Puesta en marcha: $ sudo gem install ZenTest $ AUTOFEATURE=true autospec
  • 38. Perfiles RAILS_ROOT/cucumber.yml default: --language es features html: --language es --format html features performance: --language es --format profile features
  • 39. Perfiles RAILS_ROOT/cucumber.yml default: --language es features html: --language es --format html features performance: --language es --format profile features $ cucumber --profile performance Profiling enabled. ................................................................ Top 10 average slowest steps with 5 slowest matches: 0.0048184 When /^I (try)?(?: to )?visit [quot;']?([^quot;']+)[quot;']?$/i # features/steps/when_interactions.rb:39 0.0290940 When I visit /brand-new # features/creation.feature:8 0.0038860 When I visit /brand-new # features/creation.feature:25 0.0035640 When I visit the home # features/destruction.feature:9 0.0018260 When I visit the home # features/home.feature:8 0.0017800 When I visit the home # features/destruction.feature:28 0.0039920 When /^I press [quot;']?([^quot;']+)[quot;']?$/i # features/steps/when_interactions.rb:3 0.0057240 And I press quot;sendquot; # features/creation.feature:10 0.0043170 And I press quot;sendquot; # features/edition.feature:11 0.0035290 And I press quot;sendquot; # features/creation.feature:27 0.0023980 And I press quot;sendquot; # features/edition.feature:21
  • 40. i18n lib/cucumber/languages.yml cucumber --language es feature: Característica scenario: Escenario given_scenario: DadoElEscenario given: Dado when: Cuando then: Entonces and: Y
  • 41. Ejemplo features/atencion.feature Característica: Mantener Atencion Para que todo el mundo use Cucumber Como desarollador agil Quiero mantener la atencion de la audiencia durante la ponencia Escenario: Presentando la ponencia de Cucumber Dado Que presentamos una propuesta para la Conferencia Rails 2008 Y Que nos las aceptan Y Que mandamos nuestras fotos xuflas Y Que confirmamos nuestra asistencia Y Que logramos llegar a tiempo despues de pillarnos un pedo en la cena del jueves Escenario: Crisis Temporal DadoElEscenario: Presentando la ponencia de Cucumber Y Que la audiencia comienza a quedarse sopa Cuando pulsamos “CTRL + SHIFT + R” Entonces sale una foto de unas tetas curiosas Y la gente se pone muy contenta Y algunos se rien Escenario: Exito Total DadoElEscenario: Presentando la ponencia de Cucumber Y Que la audiencia comienze a excitarse Cuando pulsamos “CTRL + R” Entonces sale una foto de media teta intrigante Y la gente se pone pensativa
  • 43. Estilo Imperativo Cuando voy a la pagina de registrarme Y relleno el campo 'email' con 'wadus@wadusland.com' Y relleno el campo 'nombre' con 'wadus' Y relleno el campo 'ciudad' con 'WadusLand' Y relleno el campo 'telefono' con '111-999-333' Y pincho en el boton 'Registrarme!' Entonces 'wadus@wadusland.com' recibira un email Y tendra como 'asunto' 'Bienvenido a WadusLand.com'
  • 44. Estilo Imperativo Cuando voy a la pagina de registrarme Y relleno el campo 'email' con 'wadus@wadusland.com' Y relleno el campo 'nombre' con 'wadus' Y relleno el campo 'ciudad' con 'WadusLand' Y relleno el campo 'telefono' con '111-999-333' Y pincho en el boton 'Registrarme!' Entonces 'wadus@wadusland.com' recibira un email Y tendra como 'asunto' 'Bienvenido a WadusLand.com' • En el estilo IMPERATIVO lo importante es, COMO se consigue el objectivo
  • 45. Estilo Declarativo Cuando un nuevo usuario se registra Entonces recibira un email con el 'asunto' 'Bienvenido a WadusLand.com'
  • 46. Estilo Declarativo Cuando un nuevo usuario se registra Entonces recibira un email con el 'asunto' 'Bienvenido a WadusLand.com' • En el estilo DECLARATIVO, lo importante es el QUE es nuestro objetivo
  • 47. Declarative vs Imperative Cual usar? pues depende del caso. Quien va a leer la historia? hombre de negocio o desarrollador? Que quieres testear y resaltar en esa historia? Arte?
  • 50. Selenium setup en The Cocktail Servidor CruiseControl: Linux Debian con Selenium-1.1.14.gem (selenium-driver, cliente) Build Secuencial (lanza APP siempre en el puerto 3000) Servidor de Selenium Remote Control: Instancia Xen con Windows XP (sin ruby instalado) java 1.6.0 & ant 1.7.0 selenium-server-0.9.2 > java -jar selenium-server.jar Resolvemos test.host y www.example.com hacia la IP CruiseControl
  • 51. The Cocktail Build task :cruise => :environment do ENV['SELENIUM_SERVER'] = quot;selenium-serverquot; ENV['SELENIUM_BROWSER'] = quot;*iexplore C:Archivos de programaMultipleIEsIE6iexplore.exequot; Rake::Task['features'].invoke Rake::Task['features_with_ajax'].invoke end Cucumber::Rake::Task.new(:features_with_ajax) do |t| t.cucumber_opts = quot;--profile ajaxquot; t.feature_pattern = quot;features/caracteristicas_ajax/**/*.featurequot; t.step_list = quot;features/step_definitions/support/selenium_env.rbquot; end Cucumber::Rake::Task.new(:features) do |t| t.cucumber_opts = quot;--profile webratquot; t.feature_pattern = quot;features/caracteristicas/**/*.featurequot; t.step_list = quot;features/step_definitions/support/webrat_env.rbquot; end selenium_env.rb app_server_pid = fork do [STDOUT, STDERR].each {|f| f.reopen('/dev/null','w')} exec quot;script/server -e #{ENV['RAILS_ENV']} -p #{apport}quot; end $selenium_driver = Selenium::SeleniumDriver.new(selenium_server, 4444, browser, appurl, 15000) $selenium_driver.start at_exit do $selenium_driver.stop Process.kill(9, app_server_pid) end
  • 52. Selenium setup en Bebanjo • Todo en el mismo Servidor (SliceHost) Ubuntu Cruise(git) gema Selenium-1.1.14 Xterm (Firefox)
  • 53. Bebanjo Build task :cruise do sh quot;script/cucumber features --profile webratquot; with_servers do sh quot;script/cucumber features --profile seleniumquot; end end def with_servers xserver_pid = run_command(quot;startx -- `which Xvfb` :1 -screen 0 1024x768x24quot;) selenium_pid = run_command(quot;sh -c 'DISPLAY=:1 selenium'quot;) webserver_pid = run_command(quot;script/server -e test -p #{ENV['WEBSERVER_PORT'] || 3000}quot;) yield ensure system(quot;killall xtermquot;) Process.kill(9, webserver_pid) require 'selenium' Selenium::SeleniumServer.new.stop end def run_command(cmd) fork do [STDOUT,STDERR].each {|f| f.reopen '/dev/null', 'w' } exec cmd end end Selenium::SeleniumDriver.new( quot;localhostquot;, 4444, quot;*chromequot;, # selenium-server, puerto, browser quot;http://localhost:3000quot;, 15000) # servidor de aplicacion, timeout
  • 54. Selenium-Grid > ant launch-hub > ant -Dport=5555 -Denvironment=quot;IExplorer6quot; launch-remote-control > ant -Dport=5556 -Denvironment=quot;Firefox3quot; launch-remote-control > ant -Dport=5557 -Denvironment=quot;GChromequot; launch-remote-control SELENIUM_BROWSERS = { :firefox => 'SELENIUM_BROWSER=quot;Firefox3quot;', :googlechrome => 'RAILS_ENV=test_chrome SELENIUM_BROWSER=quot;GChromequot; SELENIUM_APPORT=3001', :iexplorer => 'RAILS_ENV=test_iexplorer SELENIUM_BROWSER=quot;IExplorer6quot; SELENIUM_APPORT=3002' } task :features_in_selenium_grid do pids, failures_in = {}, [] SELENIUM_BROWSERS.each do |key, hash| pid = fork { exec(hash[:env] + ' SELENIUM_SERVER=selenium-server cucumber --profile selenium') } pids[pid] = key end SELENIUM_BROWSERS.size.times do Process.wait failures_in << pids[$?.pid] if $?.exitstatus == 0 end raise 'Features failure in ' + failures_in.join(' and ') unless failures_in.empty? end
  • 55. TestJour $ mkdir testjour-working-dir $ testjour slave:start $ testjour list Testjour servers: wadus available wadus-computer.local.:182499 $ testjour run features
  • 56. Ventajas • Acerca el lenguaje empleado por el cliente (o business) • Abre la spec a todos los miembros del equipo (cliente incluido) • Emerge el vocabulario de la app (comunicacion mas precisa) • Integración de toda la aplicación (JavaScript incluido) • Ausencia de quot;paginas huerfanasquot; (de forma centralizada)
  • 57. Ventajas • Acerca el lenguaje empleado por el cliente (o business) • Abre la spec a todos los miembros del equipo (cliente incluido) • Emerge el vocabulario de la app (comunicacion mas precisa) • Integración de toda la aplicación (JavaScript incluido) • Ausencia de quot;paginas huerfanasquot; (de forma centralizada) y ademas: • VERDE (no es COBOL)
  • 58. Inconvenientes • Una mismo paso se puede expresar de mil formas • lentos? • funcionalidades globales en el layout • cuando spec y cuando feature • pocas convenciones...
  • 59. Inconvenientes • lentos? • funcionalidades globales en el layout • cuando spec y cuando feature • pocas convenciones... • VERDE (no es COBOL)
  • 60. Paranoias y Deseos Imaginemos que ya tenemos todas las step_definitions escritas. Cuando escribo una nueva feature... que hago? la comiteo petando el build? me creo un rama ad-hoc? creo un archivo/directorio especial? presssssssssss? !BASTA DE NIAPAS! Scenario: with change something changes # features/edition.feature:15 Given authentication is disabled # features/steps/given_wiki.rb:6 And I have a page called quot;readmequot; with quot;Thanks!quot; # features/steps/given_wiki.rb:2 When I visit /readme # features/steps/when_interactions.rb:39 And I follow quot;Editquot; # features/steps/when_interactions.rb:11 And I fill in quot;bodyquot; with quot;This is my changed wiki page!quot; # features/steps/when_interactions.rb:15 And I press quot;sendquot; # features/steps/when_interactions.rb:3 Then I should see quot;readmequot; # features/steps/then_results.rb:2 And I should NOT see quot;Thanks!quot; # features/steps/then_results.rb:6 And I should see quot;This is my changed wiki page!quot; # features/steps/then_results.rb:2 49 steps passed 3 steps failed 11 steps skipped 1 step TODO (step definition done but pending app implementation)
  • 61. Paranoias y Deseos • Problema: tenemos features con ajax y sin ajax separadas en diferentes archivos relacionadas con la mism feature, lo queremos todo junto. • Solucion: profile por escenario (HTML / JavaScript) • Problema: Testear unobtrusive-javascript sin duplicar escenarios. • Solucion: ProfileGroup (unobtrusive = html profile + javascript profile) Ademas que en el step definition sepamos el contexto (profile!) en el que se esta/debe ejectuarse (http, javascript) • Problema: usar fit tables en un escenario con muchas variables, Solucion: no se conoce hasta ahora...
  • 62. Tip para reutilizar steps pensando en resources <li class='evento'> <p><h3>Descripcion</h3> para testear este codigo html <span>Conferencia Ruby Euroko 2009</span> </p> </li> <% content_tag_for :li, evento do %> <p class=quot;descripcionquot;> podemos usar el <%= evento.descripcion %> content_tag_for en las vistas </p> <% end %> y este step re-usable para todos los resources Then quot;he should see the text '$text' within the $resource '$resource_attribute'quot; do |text, resource, resource_attribute| response_body.should have_tag_with_child(quot;.#{resource}quot;, quot;*quot;, /#{resource_attribute}/) do with_tag(quot;*quot;, /#{text}/) end end
  • 63. Tips • /i case insensitive, mayusculas y minusculas, que mas da! • shouldify, not_shouldify • try_if_try, 40X response children = @resource.send(child_model.table_name) blog.posts child = @resource.send(child_model.name.downcase) blog.user • def unquote(text) text =~ /^['quot;](.*)['quot;]$/ ? $1 : text end end ‘edit article’, “edit article”, edit article • selenium -browserSessionReuse &
  • 64. more tips - Parentesis Grouping-only en RegExps: /(?:...)/ Por ejemplo: ...(?:(?:en|con) estado|como)?... Cazaria: Dado que la categoria BDD tiene 3 libros Y que dichos libros estan publicados o bien: Y que dichos libros estan como publicados Y que dichos libros estan en estado publicado
  • 65. anti-dolores tip • si en un step utilizamos RegExp no podemos usar variables $ • selenium setup for ie6 > java -jar selenium-server.jar -interactive ... cmd=getNewBrowserSession&1=*iexplore&2=http://test.host:3000 (...y podemos cerrar el navegador que nos abre)
  • 66. GRACIAS! • Gracias a Mamuso por el casco para volver a casa en moto a las tantas • Gracias a Macla por la foto de la ensalada • Gracias a nuestros jefes por darnos el miercoles para terminar la ponencia • Gracias a Vosotros por haber venido! • Preguntas? http://github.com/voodoorai2000/conferenciarails2008