You are on page 1of 81

Validacin de Requisitos Software: Behavior-Driven Design e Historias de Usuarios (User Stories)!

Ingeniera de Sistemas de Informacin! Grado en Ingeniera en Tecnologas de Telecomunicacin! GSyC!

2012 Departamento GSyC, URJC!


Algunos derechos reservados. Este trabajo se distribuye bajo la licencia Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License! 2012 Armando Armando Fox & David Patterson!
Licensed under Creative Commons AttributionNonCommercial-ShareAlike 3.0 Unported License!

GSyC!

2!

Contenidos!
Introduccin a Behavior Driven Design e Historias de usuarios (5.1)! Caractersticas deseables de las Historias de usuarios (5.2)! Introduccin a Cucumber y Capybara (5.3)! Ejemplo 1 de uso de Cucumber (5.4)! Bocetos de baja resolucin de la IU y Storyboards (5.5)! Ejemplo 2 de uso de Cucumber (5.6)! Requisitos explcitos vs. implcitos y Escenarios imperativos vs. declarativos (5.7)! Recomendaciones y Conclusiones (5.8-5.9)!

GSyC!

3!

Introduccin a Behavior-Driven Design e Historias de usuarios (ELLS 5.1)!

Por qu fallan los proyectos? !


No hacen lo que quieren los clientes! O no se terminan a tiempo! O cuestan ms de lo previsto! O son difciles de mantener y extender! O una combinacin de todo lo anterior! Estas observaciones son las que inspiraron las metodologas y el ciclo de vida gil!
GSyC! 5!

Ciclo de vida gil !


El primer paso es iniciar un dilogo contnuo con los actores o interesados en el proyecto (stakeholders) para denir los requisitos y los test de aceptacin que conviene llevar a acabo!
Actores: usuarios, clientes, desarrolladores, programadores de mantenimiento, operadores, gestores de proyecto, ! En myrottenpotatoes: operadores/administroadores y usuarios cinlos!

Se tiene siempre un prototipo funcional al que se le van aadiendo nuevas funcionalidades en cada iteracin!
Habitualmente cada 1 o 2 semanas! En lugar de 5 fases de varios meses cada una!

Se dialoga continuamente con el cliente !


Para descubrir lo que quiere, a veces para ayudarle a que lo descubra! Para validar el prototipo de la iteracin presente asegurndose de que se est construyendo lo que quieren ! Para acordar qu funcionalidades se aaden en la siguiente iteracin!

GSyC!

6!

Behavior-Driven Design (BDD) !


BDD permite descubrir los requisitos: hace preguntas sobre el comportamiento de la aplicacin antes y durante el desarrollo para reducir los problemas futuros de comunicacin! Los requisitos se escriben como historias de usuarios (user stories)!
Descripciones escuetas de comportamientos (behavior): cmo algn actor usar la aplicacin! Redactado en trminos del dominio de la aplicacin! Se van renando contnuamente para asegurarse de que se est programando lo que los actores quieren!

BDD se ocupa de la validacin del comportamiento de la aplicacin (QU tiene que hacer) y NO en la vericacin de la implementacin (CMO lo tiene que hacer)!
Test Driven Design (TDD) s testa la implementacin! En la prctica se va usando en cada iteracin BDD + TDD!

GSyC!

7!

Historias de usuarios (user stories)!


1-3 frases en lenguaje coloquial!
caben en tarjetas 3 x 5! Escrito por/con cliente!

Formato creado por Connextra: !


Nombre de Funcionalidad(feature)! Como un [tipo de actor (stakeholder)], Para que [yo alcance cierto objetivo], Quiero [hacer cierta tarea]!

empresa

El orden puede variar: Para que..Como un..Quiero! Al escribir una historia de usuario pensemos en ella como si fuera un futuro test de aceptacin que escribimos antes de programar el cdigo!
GSyC! 8!

Por qu tarjetas 3x5? !


Origen en la comunidad de interaccin personaordenador (Human Computer Interface)! No asusta !
todos los actores pueden participar en sesiones de lluvia de ideas!

Las tarjetas son fciles de reordenar!


todos los actores pueden participar en la asignacin de prioridades!

Al ser escuetas, son fciles de cambiar durante el desarrollo!


P.ej. Tras darse cuenta durante el desarrollo de factores no previstos antes!
GSyC! 9!

Cada tipo de actor puede denir el comportamiento de manera distinta!


Enterarme de qu amigos van a ir al cine!
Como un espectador! Para que yo pueda disfrutar de una peli con mis amigos! Quiero poder ver qu amigos planean hoy ir al cine!

Mostrarle a un cliente sus amigos de Facebook!


Como un gerente de sala de cine! Para que yo pueda animar a un cliente a que compre una entrada! Quiero poder mostrarle a mis usuarios cules de sus amigos de Facebook van hoy a ver una peli!
GSyC! 10!

Cola de peticiones (Product backlog)!


Los sistemas reales tienen cientos de historias de usuarios! Backlog: coleccin de historias de usuarios pendientes de implementar! Hay que ordenarlas segn la prioridad! Y organizarlas para que vayan pudindose testar en las versiones de SW que se vayan publicando!

GSyC!

11!

Qu afirmaciones relacionadas con BDD son FALSAS?

BDD est diseado principalmente para ayudar con la

validacin (construir lo que quiere el cliente)

BDD trata de asegurarse de que el comportamiento de la aplicacin es el esperado, no de que la implementacin es la correcta BDD implica que no hay que escribir tests de aceptacin Esta es una User Story vlida: Buscar en TMDb (servicio de info sobre pelis) Quiero poder buscar en TMDb Como un aficionado al cine Para que yo pueda encontrar informacin de nuevas pelis

GSyC!

12!

Caractersticas deseables de las historias de usuarios (ELLS 5.2)!

SMART !
Specic (Especca) ! Measurable (Medible)! Achievable (Abordable, idealmente implementable en 1 iteracin)! Relevant (Relevante, que d respuesta a 5 por qu? relacionados con el negocio)! Timeboxed (Limitada en el tiempo: saber cundo abandonar la historia de usuario)!
GSyC! 14!

Especca!
Ejemplo de funcionalidad poco especca: El usuario puede buscar una pelcula! Ejemplo de funcionalidad especca: El usuario puede buscar una pelcula por su ttulo!

GSyC!

15!

Medible!
Medible para que cada escenario pueda ser testado!
Implica que debemos poder denir una salida esperable en funcin de una entrada correcta!

Ejemplo de funcionalidad no medible: La aplicacin debe tener un buen tiempo de respuesta! Ejemplo de funcionalidad especca: Al aadir una pelcula el 99% de las veces la pgina aparece en menos de 3 segundos!
GSyC! 16!

Abordable !
Si no se puede terminar una historia de usuario en una iteracin, se entrega un nmero menor de historias!
Siempre hay que tener como objetivo disponer de cdigo que haga algo (un subconjunto de historias) al nal de una iteracin!

Se estima lo que es posible hacer usando velocity!


A cada historia se le asigna un nmero estimado de puntos (entre 1 y 3) en funcin de su dicultad estimada! Velocity == Puntos completados en cada iteracin! Se aprende de la velocity medida para planicar futuras iteraciones y ajustar la asignacin de puntos a cada historia! GSyC!

17!

Relevante: que aporte valor para el cliente!


Debe dar respuesta 5 veces a la pregunta Por qu? para descubrir el valor en trminos del negocio! Respuestas vlidas a los por qu:!
Porque protg los ingresos! Porque incrementar los ingresos! Porque reduce costes! Porque mejora la imagen de la marca! Porque mejora el producto! Porque incrementa el valor para los clientes!

GSyC!

18!

Relevante: ejemplo!
Actor que responde: gerente de sala de cine! Historia de usuario: Mostrarle a un cliente sus amigos de Facebook! 1. Por qu tenemos que aadir esa funcionalidad? Como gerente de sala de cine, creo que ayudar a que ms gente venga con amigos al cine y disfruten ms de la peli! 2. Por qu importa que disfruten ms de la peli? Creo que as venderemos ms entradas! 3. Por qu quieres vender ms entradas? Porque as tenemos ms ingresos! 4. Por qu quiere tener ms ingresos el cine? Para no echar el cierre! 5. Por qu no queremos que cierre el cine? Porque si no, no tengo trabajo !

GSyC!

19!

Limitada en el tiempo!
Paramos el esfuerzo invertido en la implementacin de una historia cuando se excede el tiempo planicado para ella.!
O la abandonamos, o la dividimos en otras ms pequeas, o replanicamos el tiempo estimado.! Si dividirla no parece que ayude, hablamos con el cliente para ver qu partes son ms importantes.!

La razn para hacerlo as es que es fcil subestimar el esfuerzo del proyecto! Si no limitamos cada iteracin el proyecto global puede alargarse mucho en el tiempo, y llegar a abortarse. !
GSyC! 20!

Qu historia de usuario es MENOS SMART? Y la que MS?

El usuario puede buscar una pelcula por ttulo

Rotten Potatoes debe tener un tiempo de respuesta bajo Al aadir una peli, el 99% de las veces se tarda menos de 3 segundos Como cliente del cine, Quiero ver las 10 pelculas ms vendidas, ordenadas por precio, Para que yo pueda comprar las ms baratas
GSyC! 21!

Introduccin a Cucumber y Capybara (ELLS 5.3)!

Cucumber !
Herramienta SW que permite convertir las historias de usuario que pueden entender los clientes del proyecto en tests de aceptacin y de integracin!
Aceptacin: nos aseguramos de que el cliente est satisfecho! Integracin: nos aseguramos de que las interfaces entre mdulos tienen precondiciones consistentes, y se comunican correctamente. !

Cucumber media entre el desarrollador y su cliente!


Las historias de usuario no parecen cdigo, por lo que las entienden los clientes y sirven para llegar a acuerdos acerca de QU se implementar! Pero tienen la suciente estructura como para permitir crear tests a partir de ellas!

GSyC!

23!

Ejemplo de historia con Cucumber !


Feature: User can manually add movie! 1 Feature / 1 historia As a moviegoer ! de usuario So that I can share with others the movies I like! I want to be able to manually add movies! Scenario: Add a movie! 1 Feature / n Escenarios Given I am on the RottenPotatoes home page (Step)! When I follow "Add new movie (Step)! Then I should be on the Create New Movie page (Step)! When I fill in "Title" with "Men In Black (Step) ! And I select "PG-13" from "Rating (Step)! And I press "Save Changes (Step)! Then I should be on the RottenPotatoes homepage(Step)! And I should see "Men In Black (Step)!

1 Escenario / 3 to 8 Pasos (steps)


GSyC! 24!

Historias de usuario en Cucumber: Feature / Scenario / Steps !


Feature: en Cucumber feature es equivalente a una historia de usuario de BDD! Escenario: muestran diferentes situaciones en las que se usa una feature! Cada Escenario tiene de 3 a 8 steps que lo describen!

GSyC!

25!

5 palabras clave para denir Pasos/Steps!


1. Given: pasos que representan el estado del mundo antes del evento, precondiciones (ej: estando en la pgina principal)! 2. When: pasos que representan un evento (ej: creo una la nueva pelcula El Padrino) ! 3. Then: pasos que representan el resultado esperado tras producirse un evento (ej: debera aparecer la pelcula aadida en la pgina principal)! 4. And y But: pasos que extienden el paso que les precede!
GSyC! 26!

Denicin de los pasos mediante expresiones regulares !


Las features/historias de usuario se guardan en un conjunto de cheros (features/*.feature) de features, que estn compuestos de steps! En un conjunto de cheros aparte (ej: features/step_denitions/ web_steps.rb) se guarda el cdigo Ruby que testa los steps: step denitions. Permiten rellenar campos, visitar pginas, pulsar botones! Las step denitions son como implementaciones de mtodos, y los steps de los escenarios son como llamadas a esos mtodos! Con expresiones regulares se hace correponder una step denition con un step:!
Step denition: ! Given /^(?:|I )am on (.+)$/ do|page_name|" visit path_to(page_name)" end Step: Given I am on the Rotten Potatoes home page"

"

GSyC!

27!

Anlisis Rojo-

-Verde !

En cuanto tenemos una feature escriba ejecutamos Cucumber ! Cucumber colorea los pasos!
Verde si se ha pasado! si no est implementado todava! Rojo si ha fallado (los pasos posteriores aparecen en Blue)!

Objetivo: convertir todos los pasos en verdes!


Verde como un pepino/cucumber!
GSyC! 28!

Capybara !
Cucumber usa capybara para ejecutar los tests! Capybara simula un browser!
Puede interaccionar con la aplicacin para recibir pginas! Procesa el HTML para comprobar el contenido de una pgina! Enva formularios como hara un usuario! Ejemplo de acciones: visit url, click_button, click_link, fill_in, check, uncheck, page.should ! Ver features/step_definitions/web_steps.rb

No puede procesar JavaScript (JS)!


Hay otra herramienta, Webdriver, que puede procesar JS!

GSyC!

29!

Instalacin y Conguracin de cucumber y capybara !


Pasamos de trabajar en el entorno de desarrollo a hacerlo en el entorno de test! Necesitamos aadir gemas de cucumber, capybara, a nuestro proyecto. Aadimos estas lneas al nal del Gemfile:!
group gem gem gem gem gem gem end

http://pastebin.com/uzdSe9pQ :test do 'cucumber-rails' 'cucumber-rails-training-wheels' # some pre-fabbed step definitions 'database_cleaner' # to clear Cucumber's test database between runs 'capybara' # lets Cucumber pretend to be a web browser 'launchy' # a useful debugging aid for user stories rspec-expectations # for .should

Aplicamos los cambios hechos a Gemle:!


bundle install --path vendor/bundle --without production GSyC! 30!

Instalacin y Conguracin de cucumber y capybara !


Cucumber necesita instalar varios directorios en nuestro proyecto, para lo cul ejecutamos:!
rails generate cucumber:install capybara rails generate cucumber_rails_training_wheels:install

Esto genera en el subdirectorio ! features/step_definitions/web_steps.rb varias deniciones de pasos (step denitions) que iremos extendiendo nosotros!

Para terminar, tenemos que inicializar, si no lo hubiramos hecho an, la base de datos de test:!
rake db:test:prepare

GSyC!

31!

Ejemplo 1 de uso de Cucumber Historia de usuario: El usuario puede aadir una peli (ELLS 5.4)!

Ejemplo !
Historia de usuario/feature: ! El usuario puede aadir una peli ! En realidad esta funcionalidad YA la hemos implementado!!
Lo hacemos para ilustrar el uso de Cucumber. Imagina que NO tenemos an implementada esa historia.!

El orden debera haber haber sido este: !


1. Escribimos la historia de usuario/feature para cucumber! 2. Usando TDD (prximo tema) implementamos los tests unitarios de la funcionalidad requerida ! 3. Implementamos el cdigo (lo que hicimos en el tema anterior)! 4. Pasamos los test unitarios con Rspec! 5. Pasamos los test de validacin/integracin con cucumber/ capybara!
GSyC! 33!

Ejemplo de historia con Cucumber !


Escribimos la historia en features/AddMovie.feature
Feature: User can manually add movie!

http://pastebin.com/mqQncg1s

Scenario: Add a movie! Given I am on the RottenPotatoes home page! When I follow "Add new movie"! Then I should be on the Create New Movie page! When I fill in "Title" with "Men In Black"! And I select "PG-13" from "Rating"! And I press "Save Changes"! Then I should be on the RottenPotatoes home page! And I should see "Men In Black"!

Ejecutamos cucumber por primera vez (usamos bundle exec para que no haya interferencia con versiones de gemas externas al proyecto): bundle exec cucumber
GSyC! 34!

Salida producida por Cucumber !


Using the default profile...! Feature: User can manually add movie! Scenario: Add a movie # features/AddMovie.feature:3!

Given I am on the RottenPotatoes home page# features/step_definitions/web_steps.rb:44! Can't find mapping from "the RottenPotatoes home page" to a path.! Now, go and add a mapping in ./features/support/paths.rb (RuntimeError)!
./features/support/paths.rb:32:in `rescue in path_to'! ./features/support/paths.rb:26:in `path_to'! ./features/step_definitions/web_steps.rb:45:in `/^(?:|I )am on (.+)$/'! features/AddMovie.feature:4:in `Given I am on the RottenPotatoes home page'! When I follow "Add new movie" # features/step_definitions/web_steps.rb:56! Then I should be on the Create New Movie page # features/step_definitions/web_steps.rb:230! When I fill in "Title" with "Men In Black" # features/step_definitions/web_steps.rb:60! And I select "PG-13" from "Rating" # features/step_definitions/web_steps.rb:85! And I press "Save Changes" # features/step_definitions/web_steps.rb:52! Then I should be on the RottenPotatoes home page # features/step_definitions/web_steps.rb:230! And I should see "Men In Black" # features/step_definitions/web_steps.rb:105! Failing Scenarios:! cucumber features/AddMovie.feature:3 # Scenario: Add a movie! 1 scenario (1 failed)! 8 steps (1 failed, 7 skipped)! 0m1.213s!

GSyC!

35!

Le hacemos caso a Cucumber !


Le hacemos caso a Cucumber y aadimos a features/ support/paths.rb una ruta adecuada para the RottenPotatoes homepage, echando mano de rake routes para la ruta de la accin index del controlador:
when /^the RottenPotatoes home page$/ movies_path

Ejecutamos de nuevo cucumber: bundle exec cucumber

GSyC!

36!

Empezamos a pasar tests !


Hemos superado ese paso, y otro ms, ambos en verde:
Using the default profile...! Feature: User can manually add movie! Scenario: Add a Given I am on When I follow Then I should movie the RottenPotatoes home page "Add new movie" be on the Create New Movie page # # # # features/AddMovie.feature:3! features/step_definitions/web_steps.rb:44! features/step_definitions/web_steps.rb:56! features/step_definitions/web_steps.rb:230!

Can't find mapping from "the Create New Movie page" to a path.!
Now, go and add a mapping in ./features/support/paths.rb (RuntimeError)! ./features/support/paths.rb:36:in `rescue in path_to'! ./features/support/paths.rb:30:in `path_to'! ./features/step_definitions/web_steps.rb:235:in `/^(?:|I )should be on (.+)$/'! features/AddMovie.feature:6:in `Then I should be on the Create New Movie page'! When I fill in "Title" with "Men In Black" # features/step_definitions/web_steps.rb:60! And I select "PG-13" from "Rating" # features/step_definitions/web_steps.rb:85! And I press "Save Changes" # features/step_definitions/web_steps.rb:52! Then I should be on the RottenPotatoes home page # features/step_definitions/web_steps.rb:230! And I should see "Men In Black" # features/step_definitions/web_steps.rb:105! Failing Scenarios:! cucumber features/AddMovie.feature:3 # Scenario: Add a movie! 1 scenario (1 failed)! 8 steps (1 failed, 5 skipped, 2 passed)! 0m1.730s!

GSyC!

37!

Volvemos a hacer caso a Cucumber !


Le hacemos caso a Cucumber y aadimos a features/ support/paths.rb una ruta adecuada para the Create New Movie page, echando mano de rake routes para la ruta de edit:
when /^the Create New Movie page$/ new_movie_path

Ejecutamos de nuevo cucumber: bundle exec cucumber

GSyC!

38!

Test de validacin superado! !


Todos los pasos del escenario, aparecen ahora verdes como un pepino (cucumber):
Using the default profile...! Feature: User can manually add movie! Scenario: Add a movie Given I am on the RottenPotatoes home page When I follow "Add new movie" Then I should be on the Create New Movie page When I fill in "Title" with "Men In Black" And I select "PG-13" from "Rating" And I press "Save Changes" Then I should be on the RottenPotatoes home page And I should see "Men In Black" 1 scenario (1 passed)! 8 steps (8 passed)! 0m1.531s! # # # # # # # # # features/AddMovie.feature:3! features/step_definitions/web_steps.rb:44! features/step_definitions/web_steps.rb:56! features/step_definitions/web_steps.rb:230 ! features/step_definitions/web_steps.rb:60! features/step_definitions/web_steps.rb:85! features/step_definitions/web_steps.rb:52! features/step_definitions/web_steps.rb:230 ! features/step_definitions/web_steps.rb:105 !

GSyC!

39!

Cul de estas armaciones sobre Cucumber y Capybara es FALSA?

Cucumber y Capybara pueden realizar tests de aceptacin e integracin

Una Feature tiene 1 User Stories, que estn compuestas de entre 3 y 8 Steps Los Steps utilizan Given para el estado actual, When para un evento/accin, y Then para las consecuencias de la accin Cucumber hace corresponder definiciones de steps con steps de un escenario usando expresiones regulares, y Capybara realiza el papel de un usuario que interacta con la aplicacin SaaS
GSyC! 40!

Bocetos de de baja resolucin de la interfaz de usuario y Storyboards (ELLS 5.5)!

Diseo de Interfaces de Usuario (IU) para SaaS !


Las aplicaciones SaaS suelen tener que ofrecer una interfaz de usuario (IU)! Las historias de usuario necesitan Interfaces de Usuario! Es preciso que todos los actores involucrados participen en el diseo de la IU!
Lo peor que puede ocurrir es que rechacen una IU despus de un montn de trabajo de desarrolladores, diseadores,!

Se necesita el equivalente de las tarjetas 3x5 para negociar la IU! Bocetos (sketches): papel y bolgrafo, y quiz tijeras y pegamento: Lo-Fi UI o IU de baja resolucin!

GSyC!

42!

Ejemplo de Lo-Fi IU !

(Figura 5.3, Engineering Long Lasting Software by Armando Fox and David Patterson, Beta edition, 2012.)

GSyC!

43!

Storyboards !
Tambin necesitamos negociar con los clientes sobre la interaccin de los usuarios con la IU! Tambin del campo de la HCI (human computer interaction) => storyboards! !
Grafo de escenas/pantallas!

Herramientas alternativas a lpiz y papel:!


Busca Wireframing tools. Ej: balsamiq, pencil project (Open Source)! Para crear bocetos y storyboards!
GSyC! 44!

Ejemplo de Storyboard !

(Figura 5.4, Engineering Long Lasting Software by Armando Fox and David Patterson, Beta edition, 2012.)

GSyC!

45!

De Lo-Fi a HTML !
Es pesado hacer bocetos y storyboards, pero ms fcil que dibujar directamente HTML + CSS + Javascript !
Tambin menos intimidante para actores no tcnicos => Es ms probable que sugieran cambios a la IU si no hay que escribir cdigo ni HTML, lo pueden modicar con sus propias manos, o hacerlo t delante de ellos! Ms probable que acepten la IU que nalmente se programe!

Una vez acordada la IU: CSS, Haml, Javascript!


Si es posible, el desarrollador + diseador slo generan la interfaz nal una vez se ha aceptado la idea de la IU inicial por parte del cliente !
En views/layouts/application/html.haml ponemos div que dan estructura a la pgina (bloque izquierda, bloque central, bloque derecho), banners, !

GSyC!

46!

Ejemplo 2 de uso de Cucumber Historia de usuario: Integracin con The Movie Database (ELLS 5.6)!

Funcionalidad: Integracin con The Movie Database (TMDb) !


Ahora s, vamos a desarrollar una nueva historia/ funcionalidad: !
Poblar la BD de pelis con pelculas provenientes de TMDb (http://www.themoviedb.org/), en lugar de introducir la informacin a mano!
Ve pidiendo una cuenta para poder usar su API: http:// www.themoviedb.org/account/signup!

Tenemos que aadir la bsqueda de pelis en TMDb a la pgina principal de Rotten Potatoes! Necesitamos escribir la feature para cucumber, un boceto de la IU LoFi y un Storyboard!
GSyC! 48!

Boceto/ Storyboard TMDb !


Dos caminos, exitoso si encontramos la peli buscada en TMDb y fallido en caso contrario. Empezaramos escribiendo un escenario para el camino exitoso y nos pondramos a implementarlo usando TDD. Como an no sabemos TDD, empezaremos escribiendo el escenario para el camino fallido y testndolo con cucumber
GSyC! 49!

Camino exitoso

Camino fallido

Historia/feature: bsqueda en TMDb, escenario para camino fallido


Creamos esta feature (por ahora slo su escenario fallido) en features/search_tmdb.feature:
Feature: El usuario puede aadir pelis que busca en The Movie Database (TMDb) As a movie fan So that I can add new movies without manual tedium I want to add movies by looking up their details in TMDb Scenario: Try to add nonexistent movie Given I am on the RottenPotatoes home page Then I should see "Search TMDb for a movie" When I fill in "Search Terms" with "Movie That Does Not Exist" And I press "Search TMDb" Then I should be on the RottenPotatoes home page And I should see "'Movie That Does Not Exist' was not found in TMDb."

http://pastebin.com/hSgk0pEK
GSyC! 50!

Corremos cucumber por primera vez !


Ejecutamos cucumber slo para esta feature: bundle exec cucumber search_tmdb.feature
Using the default profile... Feature: User can add movie by searching for it in The Movie Database (TMDb) As a movie fan So that I can add new movies without manual tedium I want to add movies by looking up their details in TMDb Scenario: Try to add nonexistent movie (sad path) Given I am on the RottenPotatoes home page # features/search_tmdb.feature:7 # features/step_definitions/web_steps.rb:44

Then I should see "Search TMDb for a movie # features/step_definitions/web_steps.rb:105 Failed assertion, no message given. (MiniTest::Assertion) ./features/step_definitions/web_steps.rb:109:in `/^(?:|I )should see "([^"]*)"$/' features/search_tmdb.feature:10:in `Then I should see "Search TMDb for a movie"'
When I fill in "Search Terms" with "Movie That Does Not Exist" And I press "Search TMDb" Then I should be on the RottenPotatoes home page And I should see "'Movie That Does Not Exist' was not found in TMDb." # # # # features/step_definitions/web_steps.rb:60 features/step_definitions/web_steps.rb:52 features/step_definitions/web_steps.rb:230 features/step_definitions/web_steps.rb:105

Failing Scenarios: cucumber features/search_tmdb.feature:7 # Scenario: Try to add nonexistent movie (sad path) 1 scenario (1 failed) 6 steps (1 failed, 4 skipped, 1 passed) 0m1.525s

GSyC!

51!

Hagamos que el paso rojo, y el siguiente azul, pasen a verde !


Aadimos form a app/views/movies/index.html.haml:
Para que Cucumber identifique Then I should see "Search TMDb for a movie"
Nueva accin que tenemos que programar y aadir su ruta en config/routes.rb!

%h1 Search TMDb for a movie

Para que Cucumber identifique When I fill in Search Terms

= form_tag :action => 'search_tmdb' do %label{:for => 'search_terms'} Search Terms = text_field_tag 'search_terms' = submit_tag 'Search TMDb'
http://pastebin.com/18yYBVbC
GSyC! 52!

Cmo identica cucumber el campo para buscar la peli? !


Este haml!
%label{:for => 'search_terms'} Search Terms = text_field_tag 'search_terms

se convierte en este HTML!


<label for='search_terms'>Search Terms</label> <input id="search_terms" name="search_terms" type="text" />

El atributo for de la etiqueta label corresponde con el atributo id de la etiqueta input, que ha sido generado por el primer parmetro del tag helper text_field_tag Esta asociacin es la que permite a cucumber saber qu campo rellenar cuando en la feature escribimos: When I fill in "Search Terms" with
GSyC! 53!

Corremos cucumber de nuevo !


Ejecutamos cucumber: bundle exec cucumber search_tmdb.feature
Using the default profile... Feature: User can add movie by searching for it in The Movie Database (TMDb) As a movie fan So that I can add new movies without manual tedium I want to add movies by looking up their details in TMDb Scenario: Try to add nonexistent movie (sad path) Given I am on the RottenPotatoes home page # features/search_tmdb.feature:7 # features/step_definitions/web_steps.rb:44

No route matches {:action=>"search_tmdb", :controller=>"movies"} (ActionView::Template::Error)


./vendor/bundle/ruby/1.9.1/gems/actionpack-3.2.8/lib/action_dispatch/routing/route_set.rb:532:in `raise_routing_error' ./vendor/bundle/ruby/1.9.1/gems/actionpack-3.2.8/lib/action_dispatch/routing/route_set.rb:528:in `rescue in generate

GSyC!

54!

Por qu falla cucumber ahora? !


MoviesController#search_tmdb es una accin del controlador que debe recibir el formulario, pero an no existe en movies_controller.rb Deberamos utilizar TDD-Test Driven Development (prximo tema) para implementar el mtodo search_tmdb En su lugar, para poder terminar el camino triste, aadimos un mtodo trucado al controlador para que siempre falle!
GSyC! 55!

Accin trucada en el controlador: Nunca encuentra una peli en TMDb!


Aadimos al controlador en app/controller/movies_controller.rb
# add to movies_controller.rb, anywhere inside # 'class MoviesController < ApplicationController': def search_tmdb # hardwired to simulate failure flash[:warning] = "'#{params[:search_terms]}' was not found in TMDb." redirect_to movies_path end

http:/pastebin.com/smwxv70i
GSyC! 56!

Ruta para la accin trucada a la que se enva el formulario !


Aadimos a config/routes.rb

# Route that posts 'Search TMDb' form post '/movies/search_tmdb'

http://pastebin.com/FrfkF6pd

GSyC!

57!

Todo verde como un cucumber! !


Ejecutamos de nuevo cucumber: bundle exec cucumber search_tmdb.feature
Using the default profile... Feature: User can add movie by searching for it in The Movie Database (TMDb) As a movie fan So that I can add new movies without manual tedium I want to add movies by looking up their details in TMDb Scenario: Try to add nonexistent movie (sad path) Given I am on the RottenPotatoes home page Then I should see "Search TMDb for a movie" When I fill in "Search Terms" with "Movie That Does Not Exist" And I press "Search TMDb" Then I should be on the RottenPotatoes home page And I should see "'Movie That Does Not Exist' was not found in TMDb." 1 scenario (1 passed) 6 steps (6 passed) 0m1.688s # # # # # # # features/search_tmdb.feature:7 features/step_definitions/web_steps.rb:44 features/step_definitions/web_steps.rb:105 features/step_definitions/web_steps.rb:60 features/step_definitions/web_steps.rb:52 features/step_definitions/web_steps.rb:230 features/step_definitions/web_steps.rb:105

GSyC!

58!

Nos falta el escenario para el camino exitoso !


Si se encuentra en TMDb una peli deberamos pasar a aadirla a nuestra BD (ver storyboard)! Al escribir el escenario exitoso los primeros pasos son los mismos que los del camino fallido:!
Given I am on the RottenPotatoes home page Then I should see "Search TMDb for a movie!

Cmo factorizamos? Recuerda, es bueno no repetirse (DRY -- Dont Repeat Yourself)! La seccin Background de una feature de cucumber tiene pasos comunes que se realizan antes de cada uno de los escenarios!
GSyC! 59!

TMDb con escenarios exitoso y fallido !


Feature: User can add movie by searching Scenario: Try to add nonexistent movie for it in The Movie Database (TMDb) (sad path) As a movie fan So that I can add new movies without manual tedium I want to add movies by looking up their details in TMDb Background: Start from the Search form on the home page Given I am on the RottenPotatoes home page Then I should see "Search TMDb for a movie" When I fill in "Search Terms" with "Movie That Does Not Exist" And I press "Search TMDb" Then I should be on the RottenPotatoes home page And I should see "'Movie That Does Not Exist' was not found in TMDb." Scenario: Try to add existing movie (happy path) When I fill in "Search Terms" with "Inception" And I press "Search TMDb" Then I should be on the "Search Results" page And I should not see "not found" And I should see "Inception" 60!

http://pastebin.com/uU3fppG9

GSyC!

El camino exitoso NO pasa el test de validacin de Cucumber !


Ejecutamos de nuevo cucumber: bundle exec cucumber search_tmdb.feature
Using the default profile... Feature: User can add movie by searching for it in The Movie Database (TMDb) As a movie fan So that I can add new movies without manual tedium I want to add movies by looking up their details in TMDb Background: Start from the Search form on the home page # features/search_tmdb.feature:7 Given I am on the RottenPotatoes home page # features/step_definitions/web_steps.rb:44 Then I should see "Search TMDb for a movie" # features/step_definitions/web_steps.rb:105

Scenario: Try to add existing movie (happy path) # features/search_tmdb.feature:19 When I fill in "Search Terms" with "Inception" # features/step_definitions/web_steps.rb:60 And I press "Search TMDb" # features/step_definitions/web_steps.rb:52

Then I should be on the "Search Results" page # features/step_definitions/web_steps.rb:230 Can't find mapping from "the "Search Results" page" to a path.

Now, go and add a mapping in ./features/support/paths.rb


./features/support/paths.rb:39:in `rescue in path_to' ./features/support/paths.rb:33:in `path_to' ./features/step_definitions/web_steps.rb:235:in `/^(?:|I )should be on (.+)$/' features/search_tmdb.feature:23:in `Then I should be on the "Search Results" page'

(RuntimeError)

GSyC!

61!

El camino exitoso falla estrepitosamente !


Normal: hemos cableado el mtodo search_tmdb para que pasen los tests del camino fallido, y as poder validar ese camino! Podramos hacer lo mismo: forzar en search_tmdb para hacer como que funciona,! Pero lo dejamos para implementarlo usando TDD en el prximo tema! Este es el proceso habitual: ! BDD -> TDD -> BDD -> TDD !
GSyC! 62!

Resumen !
Nueva historia/feature (escribimos sus pasos) => IU para la feature => escribir nuevos step denitions, incluso escribir nuevos mtodos antes de que Cucumber acabe coloreando de verde los steps! La seccin Background de un escenario permite factorizar escenarios de la misma feature! Normalmente programamos antes los caminos exitosos!
aqu no lo hicimos as por razones pedaggicas! Con TDD/RSpec (prximo tema) implementamos mtodos que acaban haciendo que todos los test de validacin/integracin de Cucumber pasen!

No se suelen cablear mtodos como search_tmdb, sino implementarlos con TDD !


BDD/Cucumber hace test de comportamientos; !
GSyC! 63!

Cierto o falso: ! ! Necesitas implementar todo el cdigo que se est testando antes de que Cucumber diga si se valida la historia de usuario

Cierto

Falso

GSyC!

64!

Requisitos explcitos vs. implcitos Escenarios imperativos vs. declarativos (ELLS 5.7)!

Requisitos explcitos vs. Implcitos !


Los requisitos explcitos son los expresados directamente en las historias de usuario, expresan el comportamiento esperado!
Ej. Como un usuario quiero poder comprar las pelculas lo ms baratas posible!

Cucumber genera test de aceptacin!

Los requisitos implcitos surgen como consecuencia lgica de los requisitos explcitos!
Ej: Le mostramos las pelculas en index ordenadas por precio, de menor a mayor! Cucumber genera test de integracin!

Escribimos historias/features explcitos e implcitos y Cucumber genera test de aceptacin e integracin!


GSyC! 66!

Escenarios Imperativos vs. Declarativos !


Escenarios Imperativos: Las primeras historias de usuario que se escriben suelen tener muchos pasos, y especican la secuencia lgica de acciones que obtiene el resultado buscado:!
Pulsar botn, rellenar campo, ! Suelen tener When And And! tiles para asegurarnos de que la IU se adeca a lo que quiere el usuario, el CMO !

Escenarios Declarativos: hablan del comportamiento, el QU, tienen muchos menos pasos y menos genricos, relacionados con el dominio de la aplicacin! Veamos una feature como ejemplo: ! las pelis deben aparecer en orden alfabtico, no en el orden ! en el que se aadieron a la BD!
Escribiremos un escenario para esta feature: mostrar la lista de pelculas despus de aadir 2 pelculas!
GSyC! 67!

Ejemplo con escenario Imperativo !


features/sorted_imperative.feature
Feature: movies should appear in alphabetical order, not added order Scenario: view movie list after adding 2 movies (imperative and non-DRY) Given I am on the RottenPotatoes home page When I follow "Add new movie" Then I should be on the Create New Movie page When I fill in "Title" with "Zorro" And I select "PG" from "Rating" And I press "Save Changes" Then I should be on the RottenPotatoes home page When I follow "Add new movie" Then I should be on the Create New Movie page When I fill in "Title" with "Apocalypse Now" And I select "R" from "Rating" And I press "Save Changes" Then I should be on the RottenPotatoes home page Then I should see "Apocalypse Now before "Zorro"
Slo el ltimo es un paso relacionado con el comportamiento (el QU) BDD/Cucumber se ocupan principalmente del QU. Los dems pasos son detalles de implementacin de la interfaz, hablan del CMO, y no del QU 68!

http://pastebin.com/Z7YbK8QK

GSyC!

Mismo ejemplo pero con escenario Declarativo !


features/sorted_declarative.feature
Feature: movies should appear in alphabetical order, not added order Scenario: view movie list after adding 2 movies (declarative and DRY) Given I have added "Zorro" with rating "PG-13" And I have added "Apocalypse Now" with rating "R" And I am on the RottenPotatoes home page Then I should see "Apocalypse Now" before "Zorro on the RottenPotatoes home page

http://pastebin.com/yL3SUraR

Necesitamos implementar las definiciones de los pasos declarativos nuevos (en rojo), antes de correr Cucumber
GSyC! 69!

Escenarios declarativos !
Los escenarios declarativos centran la atencin en el comportamiento, sus pasos tienen que ver con el dominio de la aplicacin, no con detalles de la interfaz diseada en el prototipo Los pasos declarativos son especficos a la aplicacin, no genricos, Los pasos declarativos consituyen un lenguaje de dominio de la aplicacin: I have added Zorro with rating PG-13, Veo antes Apocalypse Now que Zorro, frente a I press Save changes
GSyC! 70!

Necesitamos implementar/denir los pasos declarativos !


features/step_definition/movie_steps.rb
Given /I have added "(.*)" with rating "(.*)"/ do |title, rating| steps %Q{ Given I am on the Create New Movie page When I fill in "Title" with "#{title}" And I select "#{rating}" from "Rating" And I press "Save Changes" } end Then /I should see "(.*)" before "(.*)" on (.*)/ do |string1, string2, path| step "I am on #{path}" regexp = /#{string1}.*#{string2}/m # /m means match across newlines page.body.should =~ regexp end La pgina en la que estamos se compara con la expresin regular que fuerza el orden, y si NO hay match con la expr. reg. cucumber se para en ese paso

http://pastebin.com/rky95ycT

step y steps sirven para llamar a otros steps imperativos en los que nos apoyamos para implementar los steps declarativos Recuerda: %Q{xxx} == xxx Given = When = And = Then
GSyC! 71!

Testemos el escenario declarativo !


Ejecutamos cucumber para el escenario declarativo: bundle exec cucumber sorted_declarative.feature
bundle exec cucumber features/sorted_list_declarative.feature Using the default profile... Feature: movies when added should appear in movie list Scenario: view movie list after adding 2 movies (declarative and DRY) # features/sorted_list_declarative.feature:3 Given I have added "Zorro" with rating "PG-13" # features/step_definitions/movie_steps.rb:1 And I have added "Apocalypse Now" with rating "R" # features/step_definitions/movie_steps.rb:1 And I am on the RottenPotatoes home page # features/step_definitions/web_steps.rb:44

Then I should see "Apocalypse Now" before "Zorro" on the RottenPotatoes home page
# features/step_definitions/movie_steps.rb:10

content=\"text/html; charset=UTF-8\">\n<title>Rotten Potatoes!</title>\n<link href=\"/assets/application.css\" media=\"screen\" rel= \"stylesheet\" type=\"text/css\">\n<script src=\"/assets/application.js\" type=\"text/javascript\"></script>\n</ head>\n<body>\n<h2>All Movies</h2>\n<table id=\"movies\">\n<thead><tr>\n<th>Movie Title</th>\n<th>Rating</th> \n<th>Release Date</th>\n<th>More Info</th>\n</tr></thead>\n<tbody>\n<tr>\n<td> </td>\n<td>PG-13</td> \n<td>2012-10-16 00:00:00 UTC</td>\n<td><a href=\"/movies/1\">More about Zorro</a></td>\n</tr>\n<tr> \n<td>

expected: /Apocalypse Now.*Zorro/m got: "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-Type\"

Zorro

Apocalypse Now</td>

GSyC! 72!

Implementamos la ordenacin !
Ordenamos al mostrar en index.html.haml (hazlo t, es parte de la prctica :-) Ejecutamos de nuevo cucumber: bundle exec cucumber sorted_declarative.feature
Using the default profile... Feature: movies when added should appear in movie list Scenario: view movie list after adding 2 movies (declarative and DRY) # features/sorted_list_declarative.feature:3 Given I have added "Zorro" with rating "PG-13" # features/step_definitions/movie_steps.rb:1 And I have added "Apocalypse Now" with rating "R" # features/step_definitions/movie_steps.rb:1 And I am on the RottenPotatoes home page # features/step_definitions/web_steps.rb:44 Then I should see "Apocalypse Now" before "Zorro" on the RottenPotatoes home page # features/step_definitions/ movie_steps.rb:10 1 scenario (1 passed) 4 steps (4 passed) 0m1.864s

Tan verde como un cucumber


GSyC! 73!

Recomendaciones y Conclusiones (ELLS 5.8-5.9)!

Cuidado !
No aadas funcionalidad atractiva para ti como desarrollador que no est claro si va a hacer que el producto sea ms exitoso para el cliente!
Los clientes del proyecto pueden rechazar lo que les gusta a los programadores! Las historias de usuarios ayudan a priorizar, reduciendo el esfuerzo invertido!

GSyC!

75!

Cuidado !
No intentes predecir con demasiada antelacin qu cdigo necesitas!
BDD+TDD: escribe los test antes de escribir el cdigo que necesitas, y despus escribes el cdigo que necesitas para pasar esos tests! As no necesitas predecir qu cdigo puede hacerte falta, y no escribes cdigo innecesario!

GSyC!

76!

Cuidado !
Mejor expresar pasos Then armativamente, no negativamente! Cuidado si escribes demasiadas veces Then I should not see.!
No se puede comprobar si la salida es la esperada, slo que no es la que queras! Hay demasiadas salidas que satisfacen un paso as declarado! Mejor incluir frases armativas para comprobar los resultados en un escenario: Then I should see !
GSyC! 77!

Qu armacin acerca de Lo-FI IU y BDD es FALSA?

El objetivo de las IU Lo-Fi es depurar la IU antes de programarla

Un problema de BDD es tener que estar en contnuo contacto con los clientes, lo que no siempre es posible Un problema de BDD es que puede conducir a una arquitectura SW pobre, ya que el foco est en el comportamiento Ninguna es falsa, las tres son ciertas.
GSyC! 78!

Ventajas/Inconvenientes de BDD !
Ventaja: BDD/historias de usuarios proporciona un
lenguaje comn para todos los actores involucrados, tcnicos y no tcnicos!
Tarjetas 3x5! Bocetos Lo-Fi de la IU y storyboards! til para extraer requisitos: el cliente no siempre tiene claro qu quiere!

Ventaja: Escribes tests antes de implementar el cdigo!


Validacin mediante testing y no mediante depuracin!

Inconveniente: Puede ser difcil mantener dilogo contnuo con el cliente! Inconveniente: Puede desembocar en una arquitectura
SW no muy buena!
Lo arreglaremos en parte con patrones y refactorizacin del cdigo!
GSyC! 79!

BDD !

(Figura 5.11, Engineering Long Lasting Software by Armando Fox and David Patterson, Beta edition, 2012.)

BDD+TDD no resulta natural al principio! Las herramientas de Rails hacen fcil seguir BDD+TDD! Cada vez ms gente en la industria utiliza TDD, BDD+TDD!
GSyC! 80!

Referencias !
http://cukes.info/!

GSyC!

81!

You might also like