Kata Tenis Completa Paso a Paso. Python Sevilla 30/11/2012

Post on 02-Dec-2014

1.561 views 1 download

description

Kata tenis en Python paso a paso con

Transcript of Kata Tenis Completa Paso a Paso. Python Sevilla 30/11/2012

Kata con Python

Python-Sevilla

2

• Estudiar paso a paso cómo resolver la kata Tenis con TDD y Python

• Exponer errores y ver la manera de detectarlos.

• Comparar distintas soluciones desarrolladas con TDD.

Objetivos

Objetivos

3

1. Repaso de TDD2. Kata Tennis.3. PowerPoint-Driven

Development.4. Primer diseño (y pruebas).5. Continuamos.6. Refactorizar la clase Player.7. El Partido de Tenis.8. Random tennis9. Conclusiones.10. Otras soluciones.11. Extra

Índice

Índice

4

Repaso de TDD

2. El proceso TDD

El proceso de TDD

2. El Proceso TDD

Escribimos un test que ponga de relieve funcionalidad que queremos implementar

Si la prueba no falla estudiamos qué está sucediendo y elegimos otra.

Escribimos el código mínimo (más corto) para que la prueba pase con éxito. No nos preocupamos de

escribirlo bonito, tenemos libertad para tomar atajos

2. El Proceso TDD

Ejecutamos la prueba y cambiamos el código hasta que la prueba funciona.

Quitamos los atajos y refactorizamos el código y las pruebas.

Triangulando, completando el conjunto de pruebas o eligiendo una nueva funcionalidad.

Y cómo continuamos?

8

Kata: Tennis

9

Cata - Tenis

Reglas• un jugador comienza con puntación 0. • Los puntos se ganan en esta secuencia: 0 -> 15 -> 30 -

> 40.• Si un jugador consigue 40 y puntúa de nuevo, el

jugador gana el juego si el otro no tiene 40 puntos.• Si los dos jugadores tienen al mismo tiempo 40

puntos, se llama "iguales" (deuce en inglés)• Puntuar durante iguales, da al jugador "ventaja". Si el

otro jugador puntúa en ese momento, la puntuación vuelve a iguales.

• Si un jugador tiene "ventaja" y puntúa de nuevo, el jugador gana el juego.

http://www.solveet.com/exercises/Kata-Tennis/13

10

Cata - Tenis

Metas:• Los jugadores deben poder

ganar puntos.• El juego debe terminar con un

ganador.• Debes de manejar la casuística

de "iguales"• Después de terminar el juego,

debe determinarse quién es el ganador.

• Debe ser posible obtener la puntuación de cualquier de los jugadores en cualquier momento del partido.

11

PowerPoint-Driven Development

12

No intentes hacerlo todo de golpe.

• Elige algo pequeño y simple.• Escribe una prueba que lo

muestre.• Codifica la prueba.• Por ejemplo: pasar de 0 a 15

o el match aún no ha terminado

La primera prueba

13

¿…y ahora?

• ¿Cuál es la prueba que te hace avanzar más?

• Por ejemplo puedes continuar con las puntuaciones hasta la casuística de los 40.

• Recuerda refactorizar.

La Segunda Prueba

14

¿atascado?

• No te preocupes si tienes que volver a empezar.

• No es una pérdida de tiempo. Ya verás como la siguiente vez te sale MUCHO MEJOR.

Ha pasado el tiempo

15

¿Has terminado?

• ¿Y si intentas simular una partida de tenis con números aleatorios?.

• Refactoriza y que quede bonito

Esto se acaba

¿No has terminado?

16

Primer diseño (y pruebas)

17

Primeros pasos

Tenemos que empezar por algo. ¿Por dónde?

Mover

Metas:• Los jugadores deben poder

ganar puntos.• El juego debe terminar con un

ganador.• Debes de manejar la casuística

de "iguales"• Después de terminar el juego,

debe determinarse quién es el ganador.

• Debe ser posible obtener la puntuación de cualquier de los jugadores en cualquier momento del partido.

18

Primeros pasos

Acción Estado Resultado

-- El jugador no ha anotado ningún tanto 0 puntos

Jugador anota un tanto Sin puntos 15 puntos

Jugador anota un tanto 15 puntos 30 puntos

Jugador anota un tanto 30 puntos 40 puntos

Jugador anota un tanto 40 puntos y el otro jugador no tiene 40 puntos Gana

Jugador anota un tanto 40 puntos y el otro jugador tiene 40 puntos Ventaja

Jugador anota un tanto 40 puntos y el otro jugador tiene ventaja Se queda como está y el otro jugador vuelve a 40 puntos

Jugador anota un tanto Ventaja Gana

Ejemplos prácticos (candidatos a casos de prueba)

8 casos de prueba posibles

19

Primeros pasos

Acción Estado Resultado

-- El jugador no ha anotado ningún tanto 0 puntos

Jugador anota un tanto Sin puntos 15 puntos

Jugador anota un tanto 15 puntos 30 puntos

Jugador anota un tanto 30 puntos 40 puntos

Jugador anota un tanto 40 puntos y el otro jugador no tiene 40 puntos Gana

Jugador anota un tanto 40 puntos y el otro jugador tiene 40 puntos Ventaja

Jugador anota un tanto 40 puntos y el otro jugador tiene ventaja Se queda como está y el otro jugador vuelve a 40 puntos

Jugador anota un tanto Ventaja Gana

8 casos de prueba posibles

Manos a la obra

Primeros pasos

¿Cómo será nuestra prueba?• ¿Cómo creamos un

jugador?

1

2• No hay nada que hacer

3 • ¿Cómo conocemos la puntuación de un jugador?

• ¿Cómo se expresa la puntuación del jugadorCon nuestra primera prueba vamos a

empezar a contestar a estas preguntas y, así, veremos si elegimos una buena alternativa o

no

Primeros Pasos

También hemos tomado muchas decisiones de diseño.

He decidido crear un módulo Tennis que contiene una clase Player

He decidido utilizar un constructor sin parámetros

He decidido añadir un método sin parámetros para saber la puntuación de ese jugador

He decidido que la puntuación sea una cadena de texto

Primeros Pasos

Centramos nuestro foco en escribir el mínimo código para pasar esta prueba…

Primeros Pasos

Nada que refactorizar: ni código ni pruebas.

Para cambiar esto necesitaré más adelante una prueba que me haga

cambiarlo. A por ello.

24

Primeros pasos

Acción Estado Resultado

-- El jugador no ha anotado ningún tanto 0 puntos

Jugador anota un tanto Sin puntos 15 puntos

Jugador anota un tanto 15 puntos 30 puntos

Jugador anota un tanto 30 puntos 40 puntos

Jugador anota un tanto 40 puntos y el otro jugador no tiene 40 puntos Gana

Jugador anota un tanto 40 puntos y el otro jugador tiene 40 puntos Ventaja

Jugador anota un tanto 40 puntos y el otro jugador tiene ventaja Se queda como está y el otro jugador vuelve a 40 puntos

Jugador anota un tanto Ventaja Gana

Ejemplos prácticos (candidatos a casos de prueba)

Primeros Pasos

Podríamos refactorizar algunos detalles.

Antes Después

Triangulación.

Primeros Pasos

Ya tenemos nuestras primeras pruebas listas y nuestro código crece…. Pero,

¿qué estamos haciendo?

• Estamos diseñando cómo implementamos la puntuación de un jugador.

• Estamos diseñando cómos otras partes del código indicarán que un jugador ha puntuado.

• Estamos entrando en foco más en diseñar el código qué nos es útil que en implementar el problema.

27

Continuamos

28

Pruebas de anotación

Acción Estado Resultado

-- El jugador no ha anotado ningún tanto 0 puntos

Jugador anota un tanto Sin puntos 15 puntos

Jugador anota un tanto 15 puntos 30 puntos

Jugador anota un tanto 30 puntos 40 puntos

Jugador anota un tanto 40 puntos y el otro jugador no tiene 40 puntos Gana

Jugador anota un tanto 40 puntos y el otro jugador tiene 40 puntos Ventaja

Jugador anota un tanto 40 puntos y el otro jugador tiene ventaja Se queda como está y el otro jugador vuelve a 40 puntos

Jugador anota un tanto Ventaja Gana

Ejemplos prácticos (candidatos a casos de prueba)

Pruebas de anotación

Pruebas de anotación

Mal olor: demasiado código repetido, diseño difícil de probar.

Esta refactorización nos pone de relieve otro problema… que ignoramos

31

Pruebas de anotación

Acción Estado Resultado

-- El jugador no ha anotado ningún tanto 0 puntos

Jugador anota un tanto Sin puntos 15 puntos

Jugador anota un tanto 15 puntos 30 puntos

Jugador anota un tanto 30 puntos 40 puntos

Jugador anota un tanto 40 puntos y el otro jugador no tiene 40 puntos Gana

Jugador anota un tanto 40 puntos y el otro jugador tiene 40 puntos Ventaja

Jugador anota un tanto 40 puntos y el otro jugador tiene ventaja Se queda como está y el otro jugador vuelve a 40 puntos

Jugador anota un tanto Ventaja Gana

Ejemplos prácticos (candidatos a casos de prueba)

Parece que vamos avanzando.

32

El segundo jugador

33

Anotando con el segundo jugador

Acción Estado Resultado

-- El jugador no ha anotado ningún tanto 0 puntos

Jugador anota un tanto Sin puntos 15 puntos

Jugador anota un tanto 15 puntos 30 puntos

Jugador anota un tanto 30 puntos 40 puntos

Jugador anota un tanto 40 puntos y el otro jugador no tiene 40 puntos Gana

Jugador anota un tanto 40 puntos y el otro jugador tiene 40 puntos Ventaja

Jugador anota un tanto 40 puntos y el otro jugador tiene ventaja Se queda como está y el otro jugador vuelve a 40 puntos

Jugador anota un tanto Ventaja Gana

Necesitamos al segundo jugador.

Anotando con el segundo jugador

Las pruebas anteriores ya no se ejecutan porque no les pasaba un jugador (ni los necesitaban).

Hay que arreglarlo ?

Anotando con el segundo jugador

No ha sido una buena prueba, no he introducido nada que necesitara ni que haya hecho crecer mi código.

36

Anotando con el segundo jugador

Acción Estado Resultado

-- El jugador no ha anotado ningún tanto 0 puntos

Jugador anota un tanto Sin puntos 15 puntos

Mover derecha 15 puntos 30 puntos

Mover derecha 30 puntos 40 puntos

Mover derecha 40 puntos y el otro jugador no tiene 40 puntos Gana

Mover derecha 40 puntos y el otro jugador tiene 40 puntos Ventaja

Mover derecha 40 puntos y el otro jugador tiene ventaja Se queda como está y el otro jugador vuelve a 40 puntos

Mover derecha Ventaja Gana

Necesitamos al segundo jugador.

Hace evolucionar mi sistema.

Anotando con el segundo jugador

Las pruebas anteriores ya no se ejecutan porque a veces el segundo jugador es “None”. Hay que

arreglarlo.

Anotando con el segundo jugador

Un apaño (añadir a un segundo jugador como parámetro y hacerlo None para que mis pruebas anteriores ejecuten) olor me lleva a otro mal olor (ver si tengo un segundo jugador o no).Mejor simplificar y que todas las pruebas trabajen con un segundo jugador refactorizar.

39

Anotando con el segundo jugador

Acción Estado Resultado

-- El jugador no ha anotado ningún tanto 0 puntos

Jugador anota un tanto Sin puntos 15 puntos

Jugador anota un tanto 15 puntos 30 puntos

Jugador anota un tanto 30 puntos 40 puntos

Jugador anota un tanto 40 puntos y el otro jugador no tiene 40 puntos Gana

Jugador anota un tanto 40 puntos y el otro jugador tiene 40 puntos Ventaja

Jugador anota un tanto 40 puntos y el otro jugador tiene ventaja Se queda como está y el otro jugador vuelve a 40 puntos

Jugador anota un tanto Ventaja Gana

Necesitamos al segundo jugador.

Esta es la última prueba clave.

Anotando con el segundo jugador

41

Anotando con el segundo jugador

Acción Estado Resultado

-- El jugador no ha anotado ningún tanto 0 puntos

Jugador anota un tanto Sin puntos 15 puntos

Jugador anota un tanto 15 puntos 30 puntos

Jugador anota un tanto 30 puntos 40 puntos

Jugador anota un tanto 40 puntos y el otro jugador no tiene 40 puntos Gana

Jugador anota un tanto 40 puntos y el otro jugador tiene 40 puntos Ventaja

Jugador anota un tanto 40 puntos y el otro jugador tiene ventaja Se queda como está y el otro jugador vuelve a 40 puntos

Jugador anota un tanto Ventaja Gana

La última prueba.

Esta prueba no sería necesaria. Como vamos a ver

Anotando con el segundo jugador

Funciona !!!

Conclusiones

• Las pruebas son difíciles de entender.• He escrito código sólo para las pruebas.• He decidido cómo representar las

puntuaciones (cadenas).

Hemos terminado pero…..

Arreglémoslo.

44

Refactorizar la clase Player

Refactorizando Player

Usamos constantes

Refactorizando Player

Un mal olor que quitamos.

Refactorizando Player

No nos olvidemos de refactorizar las pruebas

Refactorizando Player

• Ahora as pruebas hablan la lógica del negocio y utilizan sus conceptos, en vez de trabajar con valores numéricos y cadenas.

• Lo que más puede cambiar está solo en un sitio.

• Tapo el apaño del constructor (a la espera de mocks).

Adiós a los malos olores.

49

El Partido de Tennis

50

El Partido de Tennis

Método winPoint

Metas:• Los jugadores deben poder

ganar puntos.• El juego debe terminar con un

ganador.• Debes de manejar la casuística

de "iguales"• Después de terminar el juego,

debe determinarse quién es el ganador.

• Debe ser posible obtener la puntuación de cualquier de los jugadores en cualquier momento del partido.

Método winPoint

Método getScore

51

El Partido de Tennis

Acción Estado Resultado

Jugador anota un tanto Dos jugadores, ningún ganador El juego continúa

Jugador anota un tanto Dos jugadores, un único ganador El juego termina. Se indica el ganador

Ejemplos prácticos (candidatos a casos de prueba)

2 casos de prueba posibles (de entrada).

Estos ejemplos de prueba no son completos. No hay que preocuparse, ya descubriremos qué falla más adelante

El Partido de Tenis

• Crear la clase match• Darle un método

playMatch• Hacer que el método anote

al jugador A

El Partido de Tenis

Podemos refactorizar el caso de prueba.

Aprovechar lo que ya tenemos del otro conjunto de pruebas

No exponer detalles de la interfaz. Actuar, no pedir

información

El Partido de Tenis

Hemos refactorizado el código en desarrollo y las pruebas.

55

El Partido de Tenis

Acción Estado Resultado

Jugador anota un tanto Dos jugadores, ningún ganador El juego continúa

Jugador anota un tanto Dos jugadores, un único ganador El juego termina. Se indica el ganador

Ejemplos prácticos (candidatos a casos de prueba)

¿Estamos a una prueba de acabar el desarrollo? Comprobémoslo

El Partido de Tennis

No hacemos nada.

57

El Partido de Tenis

Acción Estado Resultado

Jugador anota un tanto Dos jugadores, ningún ganador El juego continúa

Jugador anota un tanto Dos jugadores, un único ganador El juego termina. Se indica el ganador

Ejemplos prácticos (candidatos a casos de prueba)

Aquí falta algo

¿Qué ha pasado?

El Partido de Tenis

• Hay un valor de prueba que no estamos tratando.• ¿Cómo podemos hace que anote el otro jugador?• ¿Cómo podemos tener una prueba que siempre

puntúe B y sea ganador¿ ¿y otra en la que puntué primero A y después B?

• En verdad lo que queremos decir es….• ¿Cómo podemos cambiar lo que pasa dentro del while

en el método playmatch sin montar un follón?• ¿Hemos hecho un mal diseño y tenemos que

retroceder?• Veámoslo.

El partido de Tennis

¿Cómo podeos hacer que, en algunas pruebas puntúe el jugador A y en otras

puntúe el jugador B?

Evitamos la sobre ingeniería y buscamos la solución más sencilla que se nos ocurra

El Partido de Tennis

Vamos a reescribir las prueba para poder introducir los valores de prueba (en este caso el jugador que anota.

Nada de momento.

El Partido de Tenis

Que gane el jugador B.

Bucle infinito

Ok

El Partido de Tenis

• Hemos hecho un apaño que nos convence poco.

• ¿Estamos seguros de que funciona?• ¿Podríamos modificarlo fácilmente?• ¿Es fácil de entender?

Hemos terminado pero…..

Arreglémoslo.

El Partido de Tenis

Todo sigo funcionando.

64

El Partido de Tenis

Método winPoint

Metas:• Los jugadores deben poder

ganar puntos.• El juego debe terminar con un

ganador.• Debes de manejar la casuística

de "iguales"• Después de terminar el juego,

debe determinarse quién es el ganador.

• Debe ser posible obtener la puntuación de cualquier de los jugadores en cualquier momento del partido.

Método winPoint

Método getScore

Método winPoint

Método winPoint

65

Random Tenis

Random Tenis

• ¿Y si se calcula aleatoriamente el jugador que anota?• ¿Y si ejecuto muchos partidos seguidos y compruebo

que todo funciona correctamente?• Esto ya no son pruebas unitarias.• Si podemos hacerlo sin cambiar una coma de nuestro

código es una buena indicación.• Si tenemos que cambiar algo, lo estamos mejorando.

Vamos a hacerlo

Random Tenis

RandomPlay aún no está hecho

Random Tenis

Todo funciona a la primera

¿Por qué limitarnos a un único partido? ¿Por qué no jugamos 10.000? Vamos a hacerlo

Esto no es código de producción ,sino de pruebas

Random Tenis

Este test no debería de fallar si todo lo hicimos bien (y el test está bien escrito)

10.000 partidos……

Random Tenis

Ooops, demasiado lento. No vale para prueba unitaria.

Pues parece que funciona.

71

Conclusiones de nuestra solución

Conclusiones

• Después de 10.000 partidas no hemos detectado ningún error.

• ¿Podemos decir que el software funciona?• Nunca.• Solo estamos buscando unos errores concretos, puede

tener otros que no estemos buscando.• Los 10.000 partidas se basan en algo que no está

probado.• Si RandomScore tiene fallos, las pruebas pueden dar

falsos positivos

Conclusiones

• Notas:– No está contemplado que se siga puntuando

después de que un jugador gane (no lo pone en los requisitos pero podemos hacerlo si lo consideramos adecuado).

74

Otras soluciones

Otras soluciones

http://css.dzone.com/articles/tdd-python-5-minutes

TDD in Python in 5 minutes

Set

Score

TestSetWinning: 6 pruebas

TestScoreNames: 1 prueba

Otras soluciones

TDD in Python in 5 minutes

Otras soluciones

https://github.com/andrewnix/Kata-Tennis-Python/

Solveet. Kata TDD

Player

Método game

Sin pruebas

Otras soluciones

Método game

Otras Soluciones

https://github.com/andrewnix/Kata-Tennis-Python/

Solveet. Kata TDD

Decorador MétodoSin pruebas

Otras Soluciones

https://github.com/andrewnix/Kata-Tennis-Python/

Solveet. Kata TDD

Decorador MétodoSin pruebas

Otras Soluciones

Solveet. Kata TDD

Game

Player

Pruebas a ojo

Otras Soluciones

Game

Player

Pruebas a ojo

Otras Soluciones

Solveet. Kata TDD

84

• Consulta las soluciones si pruebas

• ¿Crees que habrían salido estas soluciones haciendo TDD?

• ¿Serías capa de escribir pruebas para ese código tal cuál está escrito, sin modificarlo?

Actividades

Autoevalua TDD

85

Extras

86

• Repositorio GitHub:https://github.com/javierj/kata-dojous

Extras

http://www.slideshare.net/Javier_J

87

Extra

Ejemplo de mocks en Python

http://iwt2-javierj.tumblr.com/post/36695988608/mocks-en-python-previa-python-tdd

Ejemplo de Behave en Python

http://iwt2-javierj.tumblr.com/post/36762766836/atdd-bdd-con-python-y-behave-previa-python-tdd

http://www.linkedin.com/groups/PythonSevilla-4685758

Python-Sevilla

Python_Sevilla / #PySVQ

https://groups.google.com/forum/?fromgroups=#!forum/python-sevilla.