¿Qué contiene tu caja de herramientas?
July 12th, 2006
Este articulo fue anteriormente publicado por Pat Eyler sobre herramientas Test-Primero (Test-first). Fue republicado por Rubylation Network y esta disponible en otros lenguajes
El enfoque de esta columna cubre en profundidad las herramientas de desarrollo basadas en pruebas (del inglés Test-First Development, Test-Driven Development, o desarrollar primero con pruebas, desarrollo guiado por pruebas). Si usted no está familiarizado con este modelo de desarrollo y desea aprender más, aquí tiene algunos buenos recursos:
- XP Magazine
- mi artículo en IBM Developerworks
- Mi anterior articulo en ZenTest
Prefiero escribir código usando este modelo ya que me siento más seguro sobre lo que escribo. Con este modelo, puedo obtener rapidamente una implementacion funcional y puedo re-estructurar facilmente todo para un mejor diseño. No es dañino que Ruby provea agradables herramientas para el trabajo de acuerdo con los principios de Probar Primero, o que algunas buenas herramientas esten disponibles para Ruby.
Mi caja de herramientas para Probar Primero incluye Test::Unit, rake, rcov, autotest y unit_diff. Las dos primeras deben ser muy familiares para la mayoria de los hackers de Ruby. Si aún no las conocen, Test::Unit se encuentra bien documentada en el libro Pick Axe y en www.ruby-doc.org. Puede leer mas sobre rake en mi articulo en IBM developerworks, y en este articulo por Martin Fowler.
Si todavia no usas Test::Unit y rake, haz un timepo para aprender a usar estas excelentes herramientas. Test::Unit es distribuido con Ruby y rake esta disponible en formato rubygem en RubyForge.
En lo que respecta a las otras herramientas en mi caja, rcov es una herramienta de analisis de cobertura de código. Cuando es ejecutada en conjunto las pruebas, genera un analisis sobre las llamadas en el codigo implementado. rcov se encuentra disponible en eigenclass.org. Usted puede generar HTML – mira este ejemplo – O una representación ASCII, en forma truncada como se muestra abajo. rcov trabaja de manera rápida; correr un programa con rcov es solo 2 o 3 veces más lento que el tiempo de ejecución normal. Adicional, rcov produce buenos y utiles resultados.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class MockDB | 2 | 0 def exec(query, &block) | 11 case query.split(' ')[3] | 5 when 'zero' | 5 num = 0 | 1 when 'one' | 4 num = 1 | 1 else | 0 num = 2 | 3 end | 0 | 0 yield [num] | 5 | 0 end | 0 | 0 end | 0 |
Puedes ejecutar rcov en conjunto con un suite de pruebas como este:
1 2 |
$ rcov test/test_hostname
|
Adicional, incluye estas opciones de linea de comandos:
- -t: genera resultados en texto sin formato.
- -T: genera resultados en texto sin formato, pero mejorado.
- -p: genera resultados de optimizacion (profiling).
- -x: excluye archivos, este parametro toma opciones como expresiones regulares separadas por comas.
- —no-html: no genera archivos HTML.
Si optas por generar resultados en texto sin formato, puede ser de utilidad redireccionarlos a un archivo. O, querrás usar ‘tee’ para un volcado a archivo—los resultados de rcov pueden ser muy extensos.
Aunque normalmente las herramientas de cobertura son empleadas para mostrar donde usted necesita escribir mas pruebas, recientemente tuve una experiencia en la cual rcov me llevo a una re-estructura (refactoring). Habia estado escribiendo código por un par de horas para comprobar el hostname. Decidí hacer una pausa y ver como cuan buena era mi cobertura de codigo. Esperaba que fuera 100%, pero muchas veces es agradable ver esto probado. Asi que me sorprendí cuando ví una banda roja al final de una banda verde. Algo no estaba siendo probado!
Revisé mi código y mis aseveraciones (assertions). Yo podia ver donde realizaba la prueba que fracasaba, pero rcov no me creía. Resultó que un chequeo que habia implementado posterior a este duplicaba mi prueba, de tal manera que mis fallas eran atrapadas antes de que siquiera llegara hasta ahi. Tuve que separar mi metodo de comprobación o eliminar el codigo sin uso. Gracias a rcov, mi código terminó siendo un método más pequeño.
La versión actual de rcov tiene un pequeño bug del cual deberán tener cuidado. Este no busca por continuaciones de linea despues de “and” o “or”. Esto requiere un parche de una sola linea en el codigo de rcov y Mauricio lo pondrá en la próxima versión.
De regreso a las otras herramientas en mi caja, autotest y unit_diff son distribuidos con ZenTes, el cual esta disponible como un rubygem. Ambos estan pensados para ayudar a alivianar las pruebas continuas en su rutina.
Con tu codigo en ./lib y sus pruebas en ./test, autotest succiona los archivos de prueba, los ejecuta y muestra los resultados. Genera un mapa entre las pruebas y los archivos de implementación, clases y metodos. Cada vez que usted guarda un archivo que esta en este mapa o crea uno que se agrega a esta lista, autotest re-ejecuta las pruebas. En el momento en que un test falla, autotest ingresa en un ciclo mas cerrado, ejecutando solamente la prueba que falla. Esto permite que usted se enfoque inmendiatamente en corregir el codigo fallante antes de proseguir.
Me tomo un par de horas de trabajo con autotest antes de que tomara el ritmo de este. Las primeras cosas que hice fueron pequeñas tareas – Actualicé un par de pruebas para Ruby 1.8.4 – de tal manera que autotest no tenia tiempo de completar su ciclo, buscar cambios y ejecutar el ciclo de pruebas nuevamente. De cualquier manera, autotest tiene una forma de lidiar con esto; presionando Ctrl-C una vez re-ejecuta las pruebas inmediatamente. Presionando la combinacion de teclas dos veces finaliza autotest.
Tambien descubrí que autotest no gusta de las pruebas que fallan al ejecutarse. Cuando estoy escribiendo codigo con Pruebas Primero, al principio de mi ciclo de desarrollo, normalmente requiero (‘require’) un archivo de implementación que no existe. Durante un desarrollo normal, es probable que incluya algun error de sintaxis o una letra. Cualquiera de estos, resulta en autotest mostrando el error generado por Ruby y luego la siguiente linea:
1 2 3 4 |
# Test::Unit murió, usted hizo algo realmente malo, reintentando en 10
|
No es lo mejor para tu ego, pero es una manera descriptiva de alzar una bandera roja y mantenerte encaminado.
unit_diff es otro pequeño programa que rapidamente se torna invalorable. Este lleva las porciones resultantes de una aseveracion fallante, lo “esperado” y lo “recibido”, empleando diff, por ende reduciendo largos bloques de texto a algo mucho mas manejable. El autor de unit_diff, Eric Hodel, dice que el programa fue escrito para ayudar con el desarrollo de ParseTree, donde una aseveración con fallas podia producir largas pantallas dificil de leer. Unit_diff convierte esta pesadilla en dos o tres lineas que muestran el error exacto. Sumado, descubrí que es invalorable cuando se trabaja con resultados en XML.
Es facil de ejecutar unit_diff. Simplemente redirecciona sus pruebas normales mediante él, de esta manera:
1 2 |
$ ruby test/test_hostname | unit_diff
|
Cualquier error que este encuentre será capturado y mostrado apropiadamente.
Espero hayas disfrutado este pequeño recorrido sobre las herramientas que ofrece Ruby sobre Test-Primero (Test-First development tools). Volvere pronto a ahablar acerca de mas temas de Ruby. Si quieres que cubra algun tema en particular, por favor sientete libre de dejar un comentario aqui.
Este articulo fue publicado el miercoles 12 de julio a las 23:00 hs. Disponible en otros lenguajes en The Rubylation Network





Leave a Reply