Kata Tenis Completa Paso a Paso. Python Sevilla 30/11/2012
description
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.