06 behavior driven design v3

81
Validación de Requisitos Software: Behavior-Driven Design e Historias de Usuarios (User Stories) Ingeniería de Sistemas de Información Grado en Ingeniería en Tecnologías de Telecomunicación GSyC

Upload: nicolas-velazco

Post on 29-Oct-2015

43 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: 06 Behavior Driven Design v3

Validación de Requisitos Software: Behavior-Driven

Design e Historias de Usuarios (User Stories)!

Ingeniería de Sistemas de Información!Grado en Ingeniería en Tecnologías de

Telecomunicación!

GSyC!

Page 2: 06 Behavior Driven Design v3

• ©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 Attribution-

NonCommercial-ShareAlike 3.0 Unported License!

2!©GSyC!

Page 3: 06 Behavior Driven Design v3

Contenidos!•  Introducción a Behavior Driven Design e Historias de

usuarios (§5.1)!•  Características deseables de las Historias de usuarios

(§5.2)!•  Introducción a Cucumber y Capybara (§5.3)!•  Ejemplo 1 de uso de Cucumber (§5.4)!•  Bocetos de baja resolución de la IU y Storyboards (§5.5)!•  Ejemplo 2 de uso de Cucumber (§5.6)!•  Requisitos explícitos vs. implícitos y Escenarios

imperativos vs. declarativos (§5.7)!•  Recomendaciones y Conclusiones (§5.8-§5.9)!

3!©GSyC!

Page 4: 06 Behavior Driven Design v3

Introducción a Behavior-Driven Design e

Historias de usuarios(ELLS §5.1)!

Page 5: 06 Behavior Driven Design v3

¿Por qué fallan los proyectos?!

• No hacen lo que quieren los clientes!• O no se terminan a tiempo!• O cuestan más de lo previsto!• O son difíciles de mantener y extender!• O una combinación de todo lo anterior!• Estas observaciones son las que

inspiraron las metodologías y el ciclo de vida ágil!

5!©GSyC!

Page 6: 06 Behavior Driven Design v3

Ciclo de vida Ágil!•  El primer paso es iniciar un diálogo contínuo con los actores o

interesados en el proyecto (stakeholders) para definir los requisitos y los test de aceptación que conviene llevar a acabo!–  Actores: usuarios, clientes, desarrolladores, programadores de

mantenimiento, operadores, gestores de proyecto, …!–  En myrottenpotatoes: operadores/administroadores y usuarios cinéfilos!

•  Se tiene siempre un prototipo funcional al que se le van añadiendo nuevas funcionalidades en cada iteración!–  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 iteración presente asegurándose de que se

está construyendo lo que quieren !–  Para acordar qué funcionalidades se añaden en la siguiente iteración!

6!©GSyC!

Page 7: 06 Behavior Driven Design v3

Behavior-Driven Design (BDD)!•  BDD permite descubrir los requisitos: hace preguntas sobre el

comportamiento de la aplicación antes y durante el desarrollo para reducir los problemas futuros de comunicación!

•  Los requisitos se escriben como historias de usuarios (user stories)!–  Descripciones escuetas de comportamientos (behavior): cómo algún

actor usará la aplicación!–  Redactado en términos del dominio de la aplicación!–  Se van refinando contínuamente para asegurarse de que se está

programando lo que los actores quieren!•  BDD se ocupa de la validación del comportamiento de la aplicación

(QUÉ tiene que hacer) y NO en la verificación de la implementación (CÓMO lo tiene que hacer)!–  Test Driven Design (TDD) sí testa la implementación!–  En la práctica se va usando en cada iteración BDD + TDD!

7!©GSyC!

Page 8: 06 Behavior Driven Design v3

Historias de usuarios (user stories)!•  1-3 frases en lenguaje coloquial!

–  caben en tarjetas 3” x 5”!–  Escrito por/con cliente!

•  Formato creado por empresa Connextra: !–  Nombre de Funcionalidad(feature)!–  Como un [tipo de actor (stakeholder)],

Para que [yo alcance cierto objetivo], Quiero [hacer cierta tarea]!

•  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 aceptación que escribimos antes de programar el código!

8!©GSyC!

Page 9: 06 Behavior Driven Design v3

¿Por qué tarjetas 3x5?!•  Origen en la comunidad de interacción persona-

ordenador (Human Computer Interface)!•  No asusta !

–  todos los actores pueden participar en sesiones de lluvia de ideas!

•  Las tarjetas son fáciles de reordenar!–  todos los actores pueden participar en la asignación de

prioridades!•  Al ser escuetas, son fáciles de cambiar durante el

desarrollo!– P.ej. Tras darse cuenta durante el desarrollo de factores

no previstos antes!

9!©GSyC!

Page 10: 06 Behavior Driven Design v3

Cada tipo de actor puede definir 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 cuáles de sus

amigos de Facebook van hoy a ver una peli!

10!©GSyC!

Page 11: 06 Behavior Driven Design v3

Cola de peticiones (Product backlog)!

•  Los sistemas reales tienen cientos de historias de usuarios!

•  Backlog: colección de historias de usuarios pendientes de implementar!

• Hay que ordenarlas según la prioridad!•  Y organizarlas para que vayan pudiéndose

testar en las versiones de SW que se vayan publicando!

11!©GSyC!

Page 12: 06 Behavior Driven Design v3

BDD trata de asegurarse de que el comportamiento de la aplicación es el esperado, no de que la implementación es la correcta

BDD implica que no hay que escribir tests de aceptación

Esta es una User Story válida: Buscar en TMDb (servicio de info sobre pelis) Quiero poder buscar en TMDb Como un aficionado al cine Para que yo pueda encontrar información de nuevas pelis

BDD está diseñado principalmente para ayudar con la validación (construir lo que quiere el cliente)

12!

¿Qué afirmaciones relacionadas con BDD son FALSAS?

©GSyC!

Page 13: 06 Behavior Driven Design v3

Características deseables de las historias de usuarios

(ELLS §5.2)!

Page 14: 06 Behavior Driven Design v3

SMART!

•  Specific (Específica) !• Measurable (Medible)!• Achievable (Abordable, idealmente

implementable en 1 iteración)!• Relevant (Relevante, que dé respuesta a 5

¿por qué? relacionados con el negocio)!•  Timeboxed (Limitada en el tiempo: saber

cuándo abandonar la historia de usuario)!

14!©GSyC!

Page 15: 06 Behavior Driven Design v3

Específica!

•  Ejemplo de funcionalidad poco específica: “El usuario puede buscar una película”!

•  Ejemplo de funcionalidad específica: “El usuario puede buscar una película por su título”!

15!©GSyC!

Page 16: 06 Behavior Driven Design v3

Medible!

• Medible para que cada escenario pueda ser testado!– Implica que debemos poder definir una salida

esperable en función de una entrada correcta!•  Ejemplo de funcionalidad no medible: “La

aplicación debe tener un buen tiempo de respuesta”!

•  Ejemplo de funcionalidad específica: “Al añadir una película el 99% de las veces la página aparece en menos de 3 segundos”!

16!©GSyC!

Page 17: 06 Behavior Driven Design v3

Abordable!•  Si no se puede terminar una historia de usuario en

una iteración, se entrega un número menor de historias!– Siempre hay que tener como objetivo disponer de

código que haga algo (un subconjunto de historias) al final de una iteración!

•  Se estima lo que es posible hacer usando velocity!– A cada historia se le asigna un número estimado de

puntos (entre 1 y 3) en función de su dificultad estimada!– Velocity == Puntos completados en cada iteración!– Se aprende de la velocity medida para planificar futuras

iteraciones y ajustar la asignación de puntos a cada historia! 17!©GSyC!

Page 18: 06 Behavior Driven Design v3

Relevante: que aporte valor para el cliente!

•  Debe dar respuesta 5 veces a la pregunta “¿Por qué?” para descubrir el valor en términos del negocio!

•  Respuestas válidas a los por qué:!– Porque protégé 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!

18!©GSyC!

Page 19: 06 Behavior Driven Design v3

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 añadir esa funcionalidad? Como gerente de

sala de cine, creo que ayudará a que más gente venga con amigos al cine y disfruten más de la peli!

2.  ¿Por qué importa que disfruten más de la peli? Creo que así venderemos más entradas!

3.  ¿Por qué quieres vender más entradas? Porque así tenemos más ingresos!

4.  ¿Por qué quiere tener más ingresos el cine? Para no echar el cierre!5.  ¿Por qué no queremos que cierre el cine? Porque si no, no tengo

trabajo !

19!©GSyC!

Page 20: 06 Behavior Driven Design v3

Limitada en el tiempo!•  Paramos el esfuerzo invertido en la

implementación de una historia cuando se excede el tiempo planificado para ella.!– O la abandonamos, o la dividimos en otras más

pequeñas, o replanificamos el tiempo estimado.!– Si dividirla no parece que ayude, hablamos con el

cliente para ver qué partes son más importantes.!•  La razón para hacerlo así es que es fácil

subestimar el esfuerzo del proyecto!•  Si no limitamos cada iteración el proyecto global

puede alargarse mucho en el tiempo, y llegar a abortarse. !

20!©GSyC!

Page 21: 06 Behavior Driven Design v3

Rotten Potatoes debe tener un tiempo de respuesta bajo

Al añadir una peli, el 99% de las veces se tarda menos de 3 segundos

Como cliente del cine, Quiero ver las 10 películas más vendidas, ordenadas por precio, Para que yo pueda comprar las más baratas

El usuario puede buscar una película por título ☐

21!

¿Qué historia de usuario es MENOS SMART? ¿Y la que MÁS?

©GSyC!

Page 22: 06 Behavior Driven Design v3

Introducción a Cucumber y Capybara

(ELLS §5.3)!

Page 23: 06 Behavior Driven Design v3

Cucumber!•  Herramienta SW que permite convertir las historias de

usuario que pueden entender los clientes del proyecto en tests de aceptación y de integración!–  Aceptación: nos aseguramos de que el cliente está satisfecho!–  Integración: nos aseguramos de que las interfaces entre módulos

tienen precondiciones consistentes, y se comunican correctamente. !

•  Cucumber media entre el desarrollador y su cliente!–  Las historias de usuario no parecen código, por lo que las

entienden los clientes y sirven para llegar a acuerdos acerca de QUÉ se implementará!

–  Pero tienen la suficiente estructura como para permitir crear tests a partir de ellas!

23!©GSyC!

Page 24: 06 Behavior Driven Design v3

Ejemplo de historia con Cucumber!Feature: User can manually add movie! As a moviegoer ! So that I can share with others the movies I like! I want to be able to manually add movies!Scenario: Add a movie! 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)!

24!

1 Escenario / 3 to 8 Pasos (steps)

1 Feature / n Escenarios

1 Feature / 1 historia de usuario

©GSyC!

Page 25: 06 Behavior Driven Design v3

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!

25!©GSyC!

Page 26: 06 Behavior Driven Design v3

5 palabras clave para definir Pasos/Steps!

1.  Given: pasos que representan el estado del mundo antes del evento, precondiciones (ej: estando en la página principal)!

2.  When: pasos que representan un evento (ej: creo una la nueva película El Padrino) !

3.  Then: pasos que representan el resultado esperado tras producirse un evento (ej: debería aparecer la película añadida en la página principal)!

4. And y But: pasos que extienden el paso que les precede!

26!©GSyC!

Page 27: 06 Behavior Driven Design v3

Definición de los pasos mediante expresiones regulares!

•  Las features/historias de usuario se guardan en un conjunto de ficheros (features/*.feature) de features, que están compuestos de steps!

•  En un conjunto de ficheros aparte (ej: features/step_definitions/web_steps.rb) se guarda el código Ruby que testa los steps: step definitions. Permiten rellenar campos, visitar páginas, pulsar botones…!

•  Las step definitions son como implementaciones de métodos, y los steps de los escenarios son como llamadas a esos métodos!

•  Con expresiones regulares se hace correponder una step definition con un step:!

–  Step definition: !Given /^(?:|I )am on (.+)$/ do |page_name|"

visit path_to(page_name)"

end"–  Step: Given I am on the Rotten Potatoes home page"

27!©GSyC!

Page 28: 06 Behavior Driven Design v3

Análisis Rojo- -Verde!

•  En cuanto tenemos una feature escriba ejecutamos Cucumber !

•  Cucumber colorea los pasos!– Verde si se ha pasado!

si no está implementado todavía!– Rojo si ha fallado

(los pasos posteriores aparecen en Blue)!

• Objetivo: convertir todos los pasos en verdes!– Verde como un pepino/cucumber!

28!©GSyC!

Page 29: 06 Behavior Driven Design v3

Capybara!

•  Cucumber usa capybara para ejecutar los tests!•  Capybara simula un browser!

–  Puede interaccionar con la aplicación para recibir páginas!–  Procesa el HTML para comprobar el contenido de una página!–  Envía formularios como haría 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!

29!©GSyC!

Page 30: 06 Behavior Driven Design v3

Instalación y Configuración de cucumber y capybara!

•  Pasamos de trabajar en el entorno de desarrollo a hacerlo en el entorno de test!

•  Necesitamos añadir gemas de cucumber, capybara,… a nuestro proyecto. Añadimos estas líneas al final del Gemfile:!

•  Aplicamos los cambios hechos a Gemfile:!

30!©GSyC!

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

http://pastebin.com/uzdSe9pQ

bundle install --path vendor/bundle --without production

Page 31: 06 Behavior Driven Design v3

Instalación y Configuración de cucumber y capybara!

•  Cucumber necesita instalar varios directorios en nuestro proyecto, para lo cuál ejecutamos:!

–  Esto genera en el subdirectorio ! features/step_definitions/web_steps.rb varias

definiciones de pasos (step definitions) que iremos extendiendo nosotros!

•  Para terminar, tenemos que inicializar, si no lo hubiéramos hecho aún, la base de datos de test:!

31!©GSyC!

rails generate cucumber:install capybara rails generate cucumber_rails_training_wheels:install

rake db:test:prepare

Page 32: 06 Behavior Driven Design v3

Ejemplo 1 de uso de Cucumber

Historia de usuario: El usuario puede añadir una peli

(ELLS §5.4)!

Page 33: 06 Behavior Driven Design v3

Ejemplo!•  Historia de usuario/feature: ! El usuario puede añadir una peli !•  ¡En realidad esta funcionalidad YA la hemos

implementado!!–  Lo hacemos para ilustrar el uso de Cucumber. Imagina que NO

tenemos aún implementada esa historia.!•  El orden debería haber haber sido este: !

1.  Escribimos la historia de usuario/feature para cucumber!2.  Usando TDD (próximo tema) implementamos los tests

unitarios de la funcionalidad requerida !3.  Implementamos el código (lo que hicimos en el tema anterior) !4.  Pasamos los test unitarios con Rspec!5.  Pasamos los test de validación/integración con cucumber/

capybara!33!©GSyC!

Page 34: 06 Behavior Driven Design v3

Ejemplo de historia con Cucumber!

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"!

34!©GSyC!

http://pastebin.com/mqQncg1s

Escribimos la historia en features/AddMovie.feature

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

Page 35: 06 Behavior Driven Design v3

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!

35!©GSyC!

Page 36: 06 Behavior Driven Design v3

Le hacemos caso a Cucumber!

when /^the RottenPotatoes home page$/

movies_path

36!©GSyC!

Le hacemos caso a Cucumber y añadimos a features/support/paths.rb una ruta adecuada para the RottenPotatoes homepage, echando mano de rake routes para la ruta de la acción index del controlador:

Ejecutamos de nuevo cucumber: bundle exec cucumber

Page 37: 06 Behavior Driven Design v3

Empezamos a pasar tests…!

37!©GSyC!

Hemos superado ese paso, y otro más, ambos en verde: 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! 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!

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!

Page 38: 06 Behavior Driven Design v3

Volvemos a hacer caso a Cucumber!

when /^the Create New Movie page$/

new_movie_path

38!©GSyC!

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

Ejecutamos de nuevo cucumber: bundle exec cucumber

Page 39: 06 Behavior Driven Design v3

¡Test de validación superado!!

39!©GSyC!

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 # features/AddMovie.feature:3! Given I am on the RottenPotatoes home page # features/step_definitions/web_steps.rb:44!

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!

1 scenario (1 passed)!8 steps (8 passed)!0m1.531s!

Page 40: 06 Behavior Driven Design v3

Una Feature tiene ≥1 User Stories, que están compuestas de entre 3 y 8 Steps

Los Steps utilizan Given para el estado actual, When para un evento/acción, y Then para las consecuencias de la acción Cucumber hace corresponder definiciones de steps con steps de un escenario usando expresiones regulares, y Capybara realiza el papel de un usuario que interactúa con la aplicación SaaS

Cucumber y Capybara pueden realizar tests de aceptación e integración

40!

¿Cuál de estas afirmaciones sobre Cucumber y Capybara es FALSA?

©GSyC!

Page 41: 06 Behavior Driven Design v3

Bocetos de de baja resolución de la interfaz de usuario y

Storyboards (ELLS §5.5)!

Page 42: 06 Behavior Driven Design v3

Diseño 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 diseño de la IU!–  Lo peor que puede ocurrir es que rechacen una IU después de un

montón de trabajo de desarrolladores, diseñadores,…!•  Se necesita el equivalente de las tarjetas 3x5 para

negociar la IU!•  Bocetos (sketches): papel y bolígrafo, y quizá tijeras y

pegamento: “Lo-Fi UI” o IU de baja resolución!

42!©GSyC!

Page 43: 06 Behavior Driven Design v3

Ejemplo de Lo-Fi IU!

43!

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

©GSyC!

Page 44: 06 Behavior Driven Design v3

Storyboards!

•  También necesitamos negociar con los clientes sobre la interacción de los usuarios con la IU!

•  También del campo de la HCI (human computer interaction) => “storyboards”! !– Grafo de escenas/pantallas!

• Herramientas alternativas a lápiz y papel:!– Busca Wireframing tools. Ej: balsamiq, pencil

project (Open Source)!– Para crear bocetos y storyboards!

44!©GSyC!

Page 45: 06 Behavior Driven Design v3

Ejemplo de Storyboard!

45!

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

©GSyC!

Page 46: 06 Behavior Driven Design v3

De Lo-Fi a HTML!

•  Es pesado hacer bocetos y storyboards, pero más fácil que dibujar directamente HTML + CSS + Javascript !–  También menos intimidante para actores no técnicos => Es más

probable que sugieran cambios a la IU si no hay que escribir código ni HTML, lo pueden modificar con sus propias manos, o hacerlo tú delante de ellos!

–  Más probable que acepten la IU que finalmente se programe!•  Una vez acordada la IU: CSS, Haml, Javascript!

–  Si es posible, el desarrollador + diseñador sólo generan la interfaz final 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 página (bloque izquierda, bloque central, bloque derecho), banners,… !

46!©GSyC!

Page 47: 06 Behavior Driven Design v3

Ejemplo 2 de uso de Cucumber

Historia de usuario: Integración con The Movie

Database (ELLS §5.6)!

Page 48: 06 Behavior Driven Design v3

Funcionalidad: Integración con The Movie Database (TMDb)!

•  Ahora sí, vamos a desarrollar una nueva historia/funcionalidad: !– Poblar la BD de pelis con películas provenientes de

TMDb (http://www.themoviedb.org/), en lugar de introducir la información a mano!

•  Ve pidiendo una cuenta para poder usar su API: http://www.themoviedb.org/account/signup!

•  Tenemos que añadir la búsqueda de pelis en TMDb a la página principal de Rotten Potatoes!

•  Necesitamos escribir la feature para cucumber, un boceto de la IU LoFi y un Storyboard!

48!©GSyC!

Page 49: 06 Behavior Driven Design v3

49!

Boceto/Storyboard

TMDb!

©GSyC!

Camino fallido Camino exitoso

• Dos caminos, exitoso si encontramos la peli buscada en TMDb y fallido en caso contrario.

• Empezaríamos escribiendo un escenario para el camino exitoso y nos pondríamos a implementarlo usando TDD.

• Como aún no sabemos TDD, empezaremos escribiendo el escenario para el camino fallido y testándolo con cucumber

Page 50: 06 Behavior Driven Design v3

Historia/feature: búsqueda en TMDb, escenario para camino fallido

Feature: El usuario puede añadir 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."

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

Creamos esta feature (por ahora sólo su escenario fallido) en features/search_tmdb.feature:

Page 51: 06 Behavior Driven Design v3

Corremos cucumber por primera vez!

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) # 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

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" # 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 RottenPotatoes home page # features/step_definitions/web_steps.rb:230

And I should see "'Movie That Does Not Exist' was not found in TMDb." # 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

51!©GSyC!

Ejecutamos cucumber sólo para esta feature: bundle exec cucumber search_tmdb.feature

Page 52: 06 Behavior Driven Design v3

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

%h1 Search TMDb for a movie

= form_tag :action => 'search_tmdb' do

%label{:for => 'search_terms'} Search Terms

= text_field_tag 'search_terms'

= submit_tag 'Search TMDb'

52!http://pastebin.com/18yYBVbC

©GSyC!

Añadimos form a app/views/movies/index.html.haml:

¡Nueva acción que tenemos que programar y añadir su ruta en config/routes.rb!

Para que Cucumber identifique Then I should see "Search TMDb for a movie"

Para que Cucumber identifique When I fill in “Search Terms”…

Page 53: 06 Behavior Driven Design v3

¿Cómo identifica 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 parámetro del tag helper text_field_tag

•  Esta asociación es la que permite a cucumber saber qué campo rellenar cuando en la feature escribimos: When I fill in "Search Terms" with

53!©GSyC!

Page 54: 06 Behavior Driven Design v3

Corremos cucumber de nuevo!

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) # features/search_tmdb.feature:7

Given I am on the RottenPotatoes home page # 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’

54!©GSyC!

Ejecutamos cucumber: bundle exec cucumber search_tmdb.feature

Page 55: 06 Behavior Driven Design v3

¿Por qué falla cucumber ahora?!

• MoviesController#search_tmdb es una acción del controlador que debe recibir el formulario, pero aún no existe en movies_controller.rb

•  Deberíamos utilizar TDD-Test Driven Development (próximo tema) para implementar el método search_tmdb

•  En su lugar, para poder terminar el camino triste, añadimos un método trucado al controlador para que siempre falle!

55!©GSyC!

Page 56: 06 Behavior Driven Design v3

Acción trucada en el controlador: Nunca encuentra una peli en TMDb !

# 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

56!

http:/pastebin.com/smwxv70i ©GSyC!

Añadimos al controlador en app/controller/movies_controller.rb

Page 57: 06 Behavior Driven Design v3

Ruta para la acción trucada a la que se envía el formulario!

# Route that posts 'Search TMDb' form

post '/movies/search_tmdb'

57!

http://pastebin.com/FrfkF6pd

©GSyC!

Añadimos a config/routes.rb

Page 58: 06 Behavior Driven Design v3

¡Todo verde como un cucumber!!

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) # 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

When I fill in "Search Terms" with "Movie That Does Not Exist" # 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 RottenPotatoes home page # features/step_definitions/web_steps.rb:230

And I should see "'Movie That Does Not Exist' was not found in TMDb." # features/step_definitions/web_steps.rb:105

1 scenario (1 passed) 6 steps (6 passed) 0m1.688s

58!©GSyC!

Ejecutamos de nuevo cucumber: bundle exec cucumber search_tmdb.feature

Page 59: 06 Behavior Driven Design v3

Nos falta el escenario para el camino exitoso!

•  Si se encuentra en TMDb una peli deberíamos pasar a añadirla 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”!•  ¿Cómo factorizamos? Recuerda, es bueno no

repetirse (DRY -- Don’t Repeat Yourself)!•  La sección Background de una feature de

cucumber tiene pasos comunes que se realizan antes de cada uno de los escenarios!

59!©GSyC!

Page 60: 06 Behavior Driven Design v3

TMDb con escenarios exitoso y fallido!

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

Given I am on the RottenPotatoes home page

Then I should see "Search TMDb for a movie"

Scenario: Try to add nonexistent movie (sad path)

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!

Page 61: 06 Behavior Driven Design v3

El camino exitoso NO pasa el test de validación de Cucumber!

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 (RuntimeError) ./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'

61!©GSyC!

Ejecutamos de nuevo cucumber: bundle exec cucumber search_tmdb.feature

Page 62: 06 Behavior Driven Design v3

El camino exitoso falla estrepitosamente!

•  Normal: hemos cableado el método search_tmdb para que pasen los tests del camino fallido, y así poder validar ese camino!

•  Podríamos hacer lo mismo: forzar en search_tmdb para hacer como que funciona,…!

•  Pero lo dejamos para implementarlo usando TDD en el próximo tema!

•  Este es el proceso habitual: ! BDD -> TDD … -> BDD -> TDD …!

62!©GSyC!

Page 63: 06 Behavior Driven Design v3

Resumen!•  Nueva historia/feature (escribimos sus pasos) => IU para

la feature => escribir nuevos step definitions, incluso escribir nuevos métodos antes de que Cucumber acabe coloreando de verde los steps!

•  La sección Background de un escenario permite factorizar escenarios de la misma feature!

•  Normalmente programamos antes los caminos exitosos!–  aquí no lo hicimos así por razones pedagógicas!–  Con TDD/RSpec (próximo tema) implementamos métodos que

acaban haciendo que todos los test de validación/integración de Cucumber pasen!

•  No se suelen “cablear” métodos como search_tmdb, sino implementarlos con TDD !–  BDD/Cucumber hace test de comportamientos; !

63!©GSyC!

Page 64: 06 Behavior Driven Design v3

Falso

Cierto ☐

64!

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

©GSyC!

Page 65: 06 Behavior Driven Design v3

Requisitos explícitos vs. implícitos

Escenarios imperativos vs. declarativos

(ELLS §5.7)!

Page 66: 06 Behavior Driven Design v3

Requisitos explícitos vs. Implícitos!

•  Los requisitos explícitos son los expresados directamente en las historias de usuario, expresan el comportamiento esperado!–  Ej. Como un usuario quiero poder comprar las películas lo más baratas

posible!–  Cucumber genera test de aceptación!

•  Los requisitos implícitos surgen como consecuencia lógica de los requisitos explícitos!–  Ej: Le mostramos las películas en index ordenadas por precio, de

menor a mayor!–  Cucumber genera test de integración!

•  Escribimos historias/features explícitos e implícitos y Cucumber genera test de aceptación e integración!

66!©GSyC!

Page 67: 06 Behavior Driven Design v3

Escenarios Imperativos vs. Declarativos!

•  Escenarios Imperativos: Las primeras historias de usuario que se escriben suelen tener muchos pasos, y especifican la secuencia lógica de acciones que obtiene el resultado buscado:!–  Pulsar botón, rellenar campo, …!–  Suelen tener When… And… And…!–  Útiles para asegurarnos de que la IU se adecúa a lo que quiere el

usuario, el CÓMO !•  Escenarios Declarativos: hablan del comportamiento, el QUÉ,

tienen muchos menos pasos y menos genéricos, relacionados con el dominio de la aplicación!

•  Veamos una feature como ejemplo: ! las pelis deben aparecer en orden alfabético, no en el orden ! en el que se añadieron a la BD!

–  Escribiremos un escenario para esta feature: mostrar la lista de películas después de añadir 2 películas!

67!©GSyC!

Page 68: 06 Behavior Driven Design v3

Ejemplo con escenario Imperativo!

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"

68!©GSyC!http://pastebin.com/Z7YbK8QK

Sólo el último es un paso relacionado con el comportamiento (el QUÉ) BDD/Cucumber se ocupan principalmente del QUÉ. Los demás pasos son detalles de implementación de la interfaz, hablan del CÓMO, y no del QUÉ

•  features/sorted_imperative.feature

Page 69: 06 Behavior Driven Design v3

Mismo ejemplo pero con escenario Declarativo!

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

69!©GSyC!

http://pastebin.com/yL3SUraR

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

•  features/sorted_declarative.feature

Page 70: 06 Behavior Driven Design v3

Escenarios declarativos!

70!©GSyC!

•  Los escenarios declarativos centran la atención en el comportamiento, sus pasos tienen que ver con el dominio de la aplicación, no con detalles de la interfaz diseñada en el prototipo

•  Los pasos declarativos son específicos a la aplicación, no genéricos,

•  Los pasos declarativos consituyen un lenguaje de dominio de la aplicación: “I have added Zorro with rating PG-13”, “Veo antes Apocalypse Now que Zorro”,…

•  frente a “I press Save changes”

Page 71: 06 Behavior Driven Design v3

Necesitamos implementar/definir los pasos declarativos!

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

71!

•  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!

http://pastebin.com/rky95ycT

•  features/step_definition/movie_steps.rb

La página en la que estamos se compara con la expresión regular que fuerza el orden, y si NO hay match con la expr. reg. cucumber se para en ese paso

Page 72: 06 Behavior Driven Design v3

Testemos el escenario declarativo!

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

expected: /Apocalypse Now.*Zorro/m

got: "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" 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>Zorro</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>Apocalypse Now</td>

… 72!©GSyC!

Ejecutamos cucumber para el escenario declarativo: bundle exec cucumber sorted_declarative.feature

Page 73: 06 Behavior Driven Design v3

Implementamos la ordenación…!

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

73!©GSyC!

Ordenamos al mostrar en index.html.haml (hazlo tú, es parte de la práctica :-)

Ejecutamos de nuevo cucumber: bundle exec cucumber sorted_declarative.feature

Tan verde como un cucumber

Page 74: 06 Behavior Driven Design v3

Recomendaciones y Conclusiones(ELLS §5.8-§5.9)!

Page 75: 06 Behavior Driven Design v3

Cuidado!

• No añadas funcionalidad atractiva para ti como desarrollador que no esté claro si va a hacer que el producto sea más 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!

75!©GSyC!

Page 76: 06 Behavior Driven Design v3

Cuidado!

• No intentes predecir con demasiada antelación qué código necesitas!– BDD+TDD: escribe los test antes de escribir el

código que necesitas, y después escribes el código que necesitas para pasar esos tests!

– Así no necesitas predecir qué código puede hacerte falta, y no escribes código innecesario!

76!©GSyC!

Page 77: 06 Behavior Driven Design v3

Cuidado!• Mejor expresar pasos Then

afirmativamente, no negativamente!• Cuidado si escribes demasiadas veces

“Then I should not see….”!– No se puede comprobar si la salida es la

esperada, sólo que no es la que querías!– Hay demasiadas salidas que satisfacen un paso

así declarado!– Mejor incluir frases afirmativas para comprobar

los resultados en un escenario:“Then I should see …”!

77!©GSyC!

Page 78: 06 Behavior Driven Design v3

Un problema de BDD es tener que estar en contínuo 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.

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

78!

¿Qué afirmación acerca de Lo-FI IU y BDD es FALSA?

©GSyC!

Page 79: 06 Behavior Driven Design v3

Ventajas/Inconvenientes de BDD!•  Ventaja: BDD/historias de usuarios proporciona un

lenguaje común para todos los actores involucrados, técnicos y no técnicos!–  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 código!–  Validación mediante testing y no mediante depuración!

•  Inconveniente: Puede ser difícil mantener diálogo contínuo con el cliente!

•  Inconveniente: Puede desembocar en una arquitectura SW no muy buena!–  Lo arreglaremos en parte con patrones y refactorización del código!

79!©GSyC!

Page 80: 06 Behavior Driven Design v3

BDD!

•  BDD+TDD no resulta natural al principio!•  Las herramientas de Rails hacen fácil seguir

BDD+TDD!• Cada vez más gente en la industria utiliza

TDD, BDD+TDD!80!

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

©GSyC!

Page 81: 06 Behavior Driven Design v3

Referencias!

•  http://cukes.info/!

81!©GSyC!