viernes, agosto 14, 2009

Introducción al TDD I

Pruebas unitarias

Introducción:


El diseño de un software es un factor muy importante pues afecta a todo el ciclo de vida del desarrollo y la calidad del software creado. Un buen diseño permite al sistema satisfacer principalmente los requisitos funcionales pero también los no funcionales como mantenibilidad, seguridad, performance, usabilidad etc. Existen varias técnicas de diseño cada una con sus características particulares. En este artículo vamos a describir los aspectos fundamentales del desarrollo de software basado en pruebas (TDD; por sus siglas en inglés).
Por lo tanto TDD no es una metodología de pruebas sino de diseño donde se comienza con el diseño y desarrollo de los casos de pruebas y luego con la implementación del código funcional hasta que las pruebas se puedan ejecutar sin errores.
Los casos de prueba además sirven para especificar los casos de uso en formato ejecutable y esta técnica permite diseñar el software en niveles de abstracción desde una granularidad chica hasta la más grande.

Beneficios de realizar las pruebas unitarias:

En cuanto al código
  • Es fácil de mantener.
  • Se torna más comprensible.
  • Tiende a estar mejor diseñado.
  • Antes de escribir código, fuerzan a detallar los requisitos de una manera útil.
  • Mientras escribe el código, evitan un exceso de funcionalidad. Cuando se pasan todos los casos de prueba, la función está completa.
  • Cuando se hace refactorización de código, aseguran que la nueva versión se comporta de la misma manera que la antigua.
  • Cuando se mantiene código, ayudan a asegurar que los cambios no alterarán código ajeno.
  • Cuando se escribe código en equipo, aumenta la confianza en que el código que se está a punto de enviar no va a romper el de otras personas, porque se pueden ejecutar las pruebas unitarias de ellos antes.
  • Los test unitarios actúan como documentación.
  • El conjunto de test unitarios proporciona constante retroalimentación de cada uno de los componentes.
  • La detección de errores se ve facilitada.
  • El tiempo de depuración se reduce.
  • El conjunto de tests actúa como una red de seguridad contra regresiones en los bugs.

Características de un buen Test:

  • Un test debe probar el qué y no el cómo, debe asegurarse que la funcionalidad del código a probar se cumpla en forma correcta y no prestar atención a como lo logra.
  • Es muy limitado en su alcance.
  • Se ejecuta y sucede de manera independiente.
  • Revela claramente su intención.
  • Debe poder ser ejecutado en forma automática cada vez que se modifique el código probado.
  • Usa ha menudo stubs y mock objects.
Desventajas de las pruebas unitarias manuales.

  • Se puede escribir una aplicación de prueba para hacer el testing. Si luego de varias semanas se quiere volver a hacer el testing el código ha sufrido tantas modificaciones que seguramente la aplicaciónd e prueba inicial ya no sirva y tenga que volver a construirse.
  • En proyectos grandes podrá haber decenas de clases y muchas librerias.Es muy dificil escribir pruebas separadas por cada una de las clases en el proyecto y mantener todas ellas para futuros pruebas.
  • Probar apliaciones requiere un tester humano.Se puede probar varias posibilidades al principio, pero es dificil recordar todos los casos para repetir en el futuro, se deberían documentar aparte teniendo que mantener los casos de pruebas y la documentación.
  • Cuando la prueba es manual, el tester debe verificar el resultado de la misma y por lo tanto deber tener todo el conjunto de resultados posibles para cada prueba
  • Es muy poco practico repetir todo el tiempo todos los casos manualmente antes de que salga un release. Esto llevaria muchas horas o días para completar las pruebas unitarias de todas las piezas de código.
  • La ejecución de pruebas unitaria en forma manual es muy tedioso y tendiente a errores.
  • Utilizando Test Driven Development TDD las pruebas son automáticas y autodocumentadas.

Herramientas

Existen en el mercado muchas herramientas que permiten realizar pruebas unitarias, la mas utilizadas son

Herramienta
Plataforma
Comentarios
NUnit
http://www.nunit.org/
.Net Framework 1.0,1.1,2.0
Free, modo consola o interface gráfica
TestDriven

http://www.testdriven.net/


.Net Framework1.0,1.1,2.0,3.0
Misma funcionalidad del NUnit como adin del VS.net.Los resultados se visulizan en modo texto en el VS.Net
JUnit

http://www.junit.org/


Java
Stand alone o integrado a varios IDEs (Eclipse, java Builder etc)
vbUnit

http://www.vbunit.com/


Visual Basic 6.0
Comercial, integrada con el VS VB 6.0
ASPUnit

http://aspunit.sourceforge.net/


ASP.Net
Permite realizar casos de prueba para el front end de ASP.Net (proyecto open source suspendido)
TFS
http://msdn.microsoft.com/en-us/teamsystem/default.aspx


.Net framework 2.0,3.0 y 3.5
Integrado con algunas versiones del Visual Studio Team System 2005/2008.
SoapUI
http://www.soapui.org

Java
Permite ejecutar pruebas unitarias de consultas SOAP y REST.

SUNit
http:\\sunit.sourceforge.net

Smaltak
El padre de todas las herramientas xUnit.

Conclusión

Las pruebas unitarias son un tema muy importante para garantizar la calidad del código que estamos creando. Usando una metodología de diseño y herramientas adecuadas este proceso se podría integrar para que en forma automática se ejecuten las pruebas unitarias ante cada subida al repositorio de código centralizado.Para ello se debería integrar con sistemas de control de versiones. Agregando un sistema de revisión de código automática junto se puede garantizar la alineación del código a estándares de codificación que mitigan problemas comunes de la aplicación de malas prácticas. Este tema está fuera del alcance del TDD pero si de las metodologías de desarrollo.

Referencias


  1. Testing object-oriented systems: models, patterns, and tools, Addison-Wesley

  1. Continuous integration, Martin Fowler, http://martinfowler.com/articles/continuousIntegration.html

  1. Extreme Programming XP , http://xprogramming.com/index.php

  1. Introducción a Scrum, http://www.mountaingoatsoftware.com/scrum

  1. Agile Manifiesto, http://agilemanifesto.org/



2 comentarios:

Fernando Claverino dijo...

Hola Sergio, muy buen post. Algo que me gustaría aportar es que para hacer TDD ayuda mucho usar tecnicas como domain driven design y patrones como inyeccion de dependencias. Sin esto, se hace muy dificil hacer test unitarios ya que dependemos, por ejemplo, de tener datos en la base de datos.

Sergio Salanitri dijo...

Gracias Fernando, el tema da para mucho, por eso le puse TDD I, no conozco sobre DDD, lo voy a investigar.
En cambio para IoC está el framework NInject. Cuando tenga algo armadopara postear lo subo.
En breve postearé la segunda parte, que se refiere al uso de herramientas de TDD como Nunit.