Vamos a empezar testeando YouTube (no es que creamos que le haga falta :-). Esto es posible por que las pruebas que haremos son de aceptación: se refieren al comportamiento de la aplicación y por tanto no es necesario siquiera que tengamos su código fuente. Nos basta con tener la posibilidad de ejecutarla.
Para las pruebas usaremos Cucumber.
Cucumber es una herramienta para escribir acceptance tests. En la metodología TDD el stackholder/parte interesada en el negocio en vez de pasarle los requisitos al equipo de desarrollo, colabora con los desarrolladores en la escritura de las pruebas que expresan el resultado que el quiere.
Es por eso que a este tipo de pruebas se las denominan acceptance tests: intentan capturar lo que el stackholder quiere.
Estas pruebas son diferentes de los tests unitarios cuyo motivo es ayudar a los desarrolladores a comprobar su diseño software.
Se suele decir que los tests unitarios nos aseguran que construimos la cosa correctamente mientras que los tests de aceptación nos aseguran que construimos la cosa correcta.
Cuando se usa Behaviour-Driven Development BDD nos preocupamos de escribir los acceptance tests como ejemplos/examples que cualquiera pueda leer y entender.
Esto es lo que Cucumber intenta: hacer que la colaboración entre stackholders y desarrolladores sean fluída.
Este es un ejemplo de test de aceptación Cucumber:
Feature: Filling a Book Review Scenario: Complete Book Review Given I am on a book review site When I submit a book review Then I should see the saved details confirmed
Nótese como las pruebas son especificadas como examples/ejemplos de como se debe conducir el sistema en un escenario concreto.
Los ficheros de features están escritos en un lenguaje que se denomina Gherkin (pepinillo).
Cuando se usa cucumber lo primero es crear un fichero features
en el que se guardan las pruebas.
Este será el scenario para testear YouTube en el fichero
features/youtube_search.features
:
$ cat youtube_search.feature Feature: Search for Videos on YouTube Scenario: Search for Videos of Large Rodents Given I am on the YouTube home page When I search for "capybara" Then videos of large rodents are returned
Esta es nuestra jerarquía de ficheros:
features/ |-- youtube_search.feature |-- step_defs | `-- steps.rb `-- support `-- env.rb
Supuesto que tenemos un fichero youtube_search.feature
pero no hemos escrito aún las step definitions,
si ejecutamos cucumber
obtenemos:
[~/sinatra/sinatra-capybara/youtube]$ cucumber Feature: Search for Videos on YouTube Scenario: Search for Videos of Large Rodents # features/youtube_search.feature:3 Given I am on the YouTube home page # features/youtube_search.feature:4 When I search for "capybara" # features/youtube_search.feature:5 Then videos of large rodents are returned # features/youtube_search.feature:6 1 scenario (1 undefined) 3 steps (3 undefined) 0m0.003s You can implement step definitions for undefined steps with these snippets: Given(/^I am on the YouTube home page$/) do pending # express the regexp above with the code you wish you had end When(/^I search for "(.*?)"$/) do |arg1| pending # express the regexp above with the code you wish you had end Then(/^videos of large rodents are returned$/) do pending # express the regexp above with the code you wish you had endCopiamos y pegamos los fragmentos de código que nos aconseja Cucumber en nuestro fichero
features/step_defs/steps.rb
.
Ahora ejecutamos cucumber
de nuevo:
~/sinatra/sinatra-capybara/youtube]$ tree . `-- features |-- step_defs | `-- steps.rb |-- support | `-- env.rb `-- youtube_search.feature 3 directories, 3 files
[~/sinatra/sinatra-capybara/youtube]$ cucumber Feature: Search for Videos on YouTube Scenario: Search for Videos of Large Rodents # features/youtube_search.feature:3 Given I am on the YouTube home page # features/step_defs/steps.rb:1 TODO (Cucumber::Pending) features/youtube_search.feature:4:in `Given I am on the YouTube home page' When I search for "capybara" # features/step_defs/steps.rb:5 Then videos of large rodents are returned # features/step_defs/steps.rb:9 1 scenario (1 pending) 3 steps (2 skipped, 1 pending) 0m0.003s
Cucumber nos informa que los pasos están por implementar.
Ahora editamos support/env.rb
:
[~/sinatra/sinatra-capybara/youtube]$ cat features/support/env.rb require 'capybara/cucumber' Capybara.default_driver = :seleniumEstamos usando Selenium WebDriver como herramienta para la automatización del navegador.
Completamos el fichero features/step_defs/steps.rb
:
[~/sinatra/sinatra-capybara/youtube]$ cat features/step_defs/steps.rb Given(/^I am on the YouTube home page$/) do visit 'http://www.youtube.com' end When(/^I search for "(.*?)"$/) do |search_term| fill_in 'search_query', :with => search_term click_on 'search-btn' end Then(/^videos of large rodents are returned$/) do puts page.inspect expect(page).to have_content 'Garibaldi' endLa llamada
fill_in 'search_query', :with => search_term
busca por un elemento del DOM que sea una text area o un text field
con un atributo name
, id
o label
establecido a search_query
y lo rellena con el
contenido de search_term
(que es capybara
).
Mirando el fuente de la página de YouTube encontramos el correspondiente tag input
con el atributo name
a search_query
:
<input id="masthead-search-term" autocomplete="off" autofocus class="search-term yt-uix-form-input-bidi" name="search_query" value="" type="text" tabindex="1" title="Search">Que tiene al lado el botón de búsqueda con un
id
igual a search-btn
:
<button class="yt-uix-button yt-uix-button-size-default yt-uix-button-default search-btn-component search-button" type="submit" onclick=" if (_gel('masthead-search-term').value == '') return false; _gel('masthead-search').submit(); return false;; return true; " id="search-btn" tabindex="2" dir="ltr" > <span class="yt-uix-button-content">Search </span>
A partir de la información search_query
Capybara es capaz de
encontrar el elemento <input>
del DOM y rellenarlo.
Cuando ejecutamos de nuevo
cucumber
se abre Firefox que navega hasta
YouTube y busca por Capybara
comprobando
que la página de resultados
contiene la palabra Garibaldi
y
produciendo un informe como este:
[~/sinatra/sinatra-capybara/youtube]$ cucumber Feature: Search for Videos on YouTube Scenario: Search for Videos of Large Rodents # features/youtube_search.feature:3 Given I am on the YouTube home page # features/step_defs/steps.rb:1 When I search for "capybara" # features/step_defs/steps.rb:5 Then videos of large rodents are returned # features/step_defs/steps.rb:10 #<Capybara::Session> 1 scenario (1 passed) 3 steps (3 passed) 0m22.491s