TDD con Python

Excelente serie de videos donde se muestra cómo hacer TDD con Python. Como dice Angel “Java” López en un post, cuando uno comienza a hacer TDD, luego no puede dejarlo. Además las herramientas utilizadas me encantaron, sobre todo pyTDDmon, que en una ventanita en colores rojo y verde nos indica el estado actual de los tests de unidad.

Este es el primero de la serie:

Los demás videos los pueden encontrar en estos links.

Es muy buena la explicación de “Java” Lopez:

Implementa algo sencillo: código que dado un string con una URL, identificar el protocolo, el dominio, y el recurso que está contenida en esa dirección. En TDD, se va escribiendo el test, el código que pasa el test, y se va progresando de a poco. No hace falta escribir el código correcto y completo desde el principio. Como en otras tantas actividades, el “baby-step”, el “pequeños pasos” de avance, nos ayuda para ir incrementalmente produciendo el resultado esperado.

Noten el ciclo rojo-verde-refactor, el código mínimo que se agrega en cada tests (a veces, retornando valores puestos a mano, sólo para pasar los tests), refactorizando el test si hay código duplicado, las micro-decisiones de diseño que se van tomando, etc… Excelente trabajo para mostrar en video!

Además otra cosa interesante, no directamente relacionado con TDD pero si con las pruebas de unidad, es la cantidad de veces que el autor prueba distintas implementaciones sin preocuparse, ya que tiene toda una suite de tests para saber si la misma es válida. Eso es algo hermoso 🙂

En Making Good Software, leí una vez un post muy interesante titulado “TDD is not about testing!!!” que me llamó mucho la atención al principio. Mucha gente piensa que escribir los tests primero es hacer TDD, lo cual es incorrecto. TDD es una práctica de diseño, y es todo un proceso:

Test-driven development

Publicado por

miltondp

Soy Ingeniero en Sistemas de Información y actualmente vivo en la ciudad de Santa Fe (Capital), Argentina. Estoy haciendo un Doctorado en Ingeniería, y me gusta mucho leer, y de vez en cuando escribir.

  • La existencia de esos frameworks para testing realmente facilitan mucho las cosas. Recuerdo el trabajo que hicimos hace poco Milton y la verdad el laburo que te tomó implementar un tester para lo que necesitabamos fue grande dado que la situación era especial (había que probar el comportamiento de espresiones regulares dentro de consultas SQL en PostgreSQL).

    Ahora, me surge una duda, ¿cómo seteas la frecuencia del ciclo entre escribir código y correr los test y escribir test nuevos? O sea, cada cuánto conviene volverse a los test. Siempre que veo ejemplos de práctica como estas están lejos de cómo las aplico.

    Quisiera saber si vos, o algún otro visitante del blog le pasa lo mismo. Está bien que los ejemplos siempre son triviales en los tutoriales, pero ¿se codifica siempre así, de soluciones tan sencillas que parecen absurdas cuando el objetivo perseguido era otro?.

    Saludos y gracias por sacar estos temas!

  • Yo creo que la respuesta a tu pregunta sobre la frecuencia es que cuando necesito diseñar e implementar algo nuevo ahí es donde vuelvo a los tests. Comienzo escribiendo las pruebas antes de implementar. Realizo el diseño testeando, y me parece que es una excelente forma de diseñar la API y el funcionamiento del módulo.

    Con respecto a lo otro, a implementar algo absurdo (como devolver un valor constante, como en el ejemplo), puede parece ilógico, pero creo que gano en dos aspectos:

    • Voy a llegar a la solución más simple para todos los casos contemplados.
    • El desarrollo realmente está dirigido por pruebas: si no hay una prueba que me lo exija, no lo codifico, no es necesario. Esto me obliga a tener una buena suite de pruebas (que contemple todos los casos posibles), y al mismo tiempo, a pensar en la solución más fácil.

    Como un ejemplo más o menos acertado, hoy estaba discutiendo con un usuario de Buildbot acerca de cómo solucionar el bug que tiene al funcionar con Mercurial usando URLs con el usuario y contraseña, que lo publiqué en un post. La idea final fue implementar la solución completamente en Buildbot, sin parchear Mercurial. Al principio habíamos dicho de usar expresiones regulares. Cuando vi este ejemplo de TDD con Python, y al estar escrito Buildbot en este lenguaje, aproveché para probar las herramientas (me encantó pyTDDmon). La solución a la que llegué fue usando la función split y dividiendo la URL para quitar el usuario y la contraseña del mismo. No usé expresiones regulares y me parece que la solución final terminó siendo más simple. Si más adelante surge otro caso especial más complejo, quizá la solución más simple sea usar expresiones regulares en lugar de seguir extendiendo lo implementado con el mismo enfoque.

  • Está bien lo que decís acerca de mantener la solución simple, pero vuelvo justo al ejemplo del video. El tipo quiere extraer el protocolo y la parte del dominio. Ese es su requerimiento. Me parece que como todo hay que tener un balance, es decir, usar TDD pero si el requermiento es extraer la parte del dominio hacer pruebas en base al requerimiento y no a una sola entrada posible. En otras palabras escribir una chorrera de casos de prueba y luego programar para extraer el dominio, que es algo bien definido y ubicable en la cadena.

    Creo que es importante balancear todo lo que estuvimos aprendiendo estos años, y entremezclar un buen diseño, con una buena solución con todas las otras “principios” que están en boca (DRY, KISS, SOC, YAGNI, …). De hecho la mayoría de las veces cuando se explican estos principios o alguna de las prácticas como TDD se les olvida explicar acerca de no hacer abuso. Todos los abusos son malos 🙂

    Para resumir la idea: si vamos a estar en un equipo que diseña, programa y proyecta, tenemos que ser el balance de las tres cosas, ya que tenemos experiencia en gestión de proyectos, en diseño y en programación. Aprovechemos ese potencial y no nos comportemos sólo como programadores o diseñadores refactoreadores o gestores de proyectos.

    Un abrazo!

  • No me parece que haya conflictos entre usar la práctica y cumplir los requerimientos, al contrario. Simplemente es otro enfoque para alcanzarlos. Justamente, por eso va agregando más tests de unidad y no se queda con una sola entrada posible. En vez de escribir todos los tests de entrada como vos decís, con esta práctica escribís un test, verificás que falle, implementas un poco, escribís otro test… y así dando pequeños pasos vas diseñando la solución y refactoreando hasta alcanzar los requerimientos, siempre dirigido por las pruebas. Además, hay que tener en cuenta que esta es una práctica. Obviamente que, si es necesario, además necesitas una metodología de gestión del proyecto.

    A mí me gustó un consejo que leí cuando estaba aprendiendo eXtreme Programming: ir armando mi propio proceso, por supuesto, pero no apurarme con los cambios en el mismo, en las etapas iniciales usar la metodología tal cual se indica, ver cómo funciona y asegurarme de que entendí la idea, y recién después cambiar si es necesario.

  • Hugo

    Les dejo un tutorial que amplia la explicación de TDD en Python, ojalá les sirva.

    http://camello.hourb.com/desarrollo-guiado-por-pruebas-en-python/