Test-Driven Development

Anuncio
Desarrollo de Software
conducido por Pruebas
Test-Driven Development
Aportes de: Agustín Goñi – Microsoft Cono Sur
Temario
•
•
•
•
•
Testeo de aplicaciones
Desarrollo conducido por las pruebas
Impacto en el proceso de desarrollo
Herramientas para TDD
Buenas prácticas y recomendaciones
Desarrollo conducido por pruebas
• Procesos de desarrollo tradicionales
– Etapas de análisis, diseño, implementación y
testeo claramente separadas.
– Asumen un diseño correcto al primer intento.
– Se espera a tener el componente o pieza de
software implementado para hacer pruebas.
– Fallas en la etapa de testing significan tener
que rehacer muchas trabajo.
– Alto costo e impacto.
Desarrollo conducido por la prueba
• Procesos de espiral
– Se construye por iteración.
– Las etapas están separadas dentro de cada
iteración, pero no en el proyecto completo.
– Se reduce el riesgo de detectar tardíamente
errores de muy alto costo.
– A pesar de todo es necesario construir antes
de comenzar el testing.
Inconvenientes y problemas
• Degradación del diseño
– Las pruebas se dejan para el final.
– Los errores pequeños no son detectados a
tiempo y se propagan.
– Los errores del componente se arreglan
“extraoficialmente”.
– El diseño no corresponde a la realidad; es el
código el que manda.
Temario
•
•
•
•
•
Testeo de aplicaciones
Desarrollo conducido por las pruebas
Impacto en el proceso de desarrollo
Herramientas para TDD
Buenas prácticas y recomendaciones
Desarrollo conducido por la prueba
• ¿Qué es el desarrollo conducido por la
prueba?
– Una técnica para la construcción de software
que consiste en producir pruebas unitarias
automáticas antes de escribir el código.
– Proviene de la filosofía de Extreme
Programming, buscando un proceso de
desarrollo más ágil.
Desarrollo conducido por la prueba
• ¿Por qué antes?
– Es una forma de prevenir defectos.
– Permite analizarlos y contenerlos antes que se
introduzcan en el código.
– Busca detectar los errores antes en vez de
arreglarlos después.
Desarrollo conducido por la prueba
¿Cómo funciona? Æ Esquema Red/Green/Refactor
1. El desarrollador escribe tests unitarios para el
componente que está por construir.
2. Compila (lo cual debería fallar: no se ha
implementado)
3. Escribe código sólo para que compile.
4. Corre el test (lo cual debería fallar).
5. Arregla el código para que pase el test.
6. Corre el test y ve que pasa OK.
7. Hace refactoring del código para eliminar la
duplicación y hacerlo más legible y mantenible
8. Vuelve a repetir.
Desarrollo conducido por la prueba
• ¿Cómo se realiza la prueba unitaria?
– Los desarrolladores ejecutan el código para
verificar que cumple los requisitos del diseño.
– Si se encuentran defectos se hace debug.
– Estas actividades se alternan con la
codificación.
– Muchas veces se agrega código de prueba
para ejecutar el componente.
Desarrollo conducido por la prueba
• Código de prueba
– A veces luego de terminado el desarrollo, se
descarta el código de prueba.
– A veces se guarda, pero mezclado con el
código de producción (ej. en un método de
prueba).
– Como la prueba unitaria es responsabilidad del
desarrollador, en general no se define un
estándar para ordenar el código de prueba.
Desarrollo conducido por la prueba
• ¿Porque es un conductor del desarrollo?
– El conjunto de prueba define una
especificación programática del componente.
– Hacerlo antes del desarrollo permite tener un
criterio de satisfacción de los requisitos de
diseño.
– Es una guía de lo que se debe implementar.
– Más importante, es un mecanismo que permite
al diseño evolucionar.
– Se postergan las decisiones hasta tener
información más completa.
Desarrollo conducido por la prueba
• Proceso simple
– El desarrollador hace la prueba con las
mismas herramientas que usa y en el mismo
lenguaje de programación.
– Ordena prácticas que ya están presentes y
ayuda a darle foco a la prueba.
Temario
•
•
•
•
•
Testeo de aplicaciones
Desarrollo conducido por las pruebas
Impacto en el proceso de desarrollo
Herramientas para TDD
Buenas prácticas y recomendaciones
Impacto en el proceso de desarrollo
• El desarrollo conducido por la prueba
afecta varias áreas del desarrollo:
– Prevención de defectos.
– Mantenimiento.
– Diseño simple.
– Confianza del desarrollador.
– Documentación.
– Trabajo en equipo.
Impacto en el proceso de desarrollo
• Prevención de defectos
– Es el impacto directo de la técnica.
– Se produce código con menos defectos, se
previenen y corrigen muy temprano.
– El conjunto de casos de prueba unitaria hace
que el software sea auto-verificable.
Impacto en el proceso de desarrollo
• Mantenimiento
– Repetir las pruebas muchas veces es fácil,
agiliza el ciclo de desarrollo y el
mantenimiento.
– Cuando tenemos que realizar un cambio es
menos riesgoso romper algo.
– Contamos con una especificación
programática del comportamiento.
Impacto en el proceso de desarrollo
• Diseño simple
– Guía al desarrollador a un diseño simple.
– Generalmente un diseño fácil de probar es un
buen diseño.
– Conduce a una interfaz simple y evita el
acoplamiento.
– Al implementar la interfaz se hace lo mínimo
necesario para satisfacer el test.
Impacto en el proceso de desarrollo
• Confianza del desarrollador
– El método incentiva los incrementos pequeños
fácilmente verificables.
– Se puede hacer una modificación y saber
inmediatamente si todo sigue funcionando.
– Refactoring del código con muy poco peligro
de romper algo.
Impacto en el proceso de desarrollo
• Documentación
– Los casos de prueba constituyen una
documentación muy completa del
comportamiento del componente.
Impacto en el proceso de desarrollo
• Trabajo en equipo
– Relacionado con las prácticas de XP
– La facilidad de cambiar la funcionalidad se
traslada fácilmente a todos los miembros.
– Lo importante es que se cumplan las pruebas
sin importar quien modifique el componente.
– No hay propietarios.
Temario
•
•
•
•
•
Testeo de aplicaciones
Desarrollo conducido por las pruebas
Impacto en el proceso de desarrollo
Herramientas para TDD
Buenas prácticas y recomendaciones
Herramientas para TDD
• Para poner todo esto en práctica
necesitamos una herramienta que permita:
– Definir tests unitarios.
– Ejecutarlos de manera automática.
– Mantenerlos independientes del código de la
aplicación.
– Hacer cambios y volver a correr los tests de
manera transparente.
– Proveer una interfaz de usuario clara e
informativa.
Herramientas para TDD
• Se han desarrollado varias opciones:
– Originalmente el framework XUnit para C/C++
sobre Unix.
– JUnit para Java basado en ese framework,
creado por Erich Gamma y Kent Beck
– Nunit, MbUnit para .NET.
– Varios otros para lenguajes/ambientes
específicos.
– Algunas herramientas de desarrollo lo están
incorporando en la IDE.
Herramienta NUnit
• Definiendo NUnit
– Cumple con las condiciones que se busca en
una herramienta de TDD.
– Es un conjunto de clases (framework) que se
extienden por herencia.
– Es una herramienta de diseño muy simple.
– Las pruebas se pueden codificar en cualquier
lenguaje .NET.
Herramienta NUnit
• Radiografía de un caso de prueba:
– Estímulo
– Respuesta
– Evaluación
• Ejemplo (C#)
[Test]
public void PushOne()
{
stack.Push(“first element”);
Assert.IsFalse(stack.IsEmpty);
}
Herramienta NUnit
• Ejecución utilizando TestRunners
Herramienta NUnit
• Atributos en NUnit 2.x
– A partir de la versión 2 se utilizan atributos.
– Nos permiten atribuir características al
código, en un nivel de abstracción diferente al
de la funcionalidad.
Herramienta NUnit
• Ejemplo de atributos en NUnit
– <Test()> Define un método de prueba
– <TestFixture()> Define una clase que contiene
métodos de prueba
– <ExpectedException(Excepcion)> Cuando el
resultado esperado es una excepción
– <Ignore(“Mensaje”)> No se corre la prueba,
pero da una alerta amarilla.
– <SetUp()> Método de inicialización del fixture
– <TearDown()> Método de finalización
Demo NUnit y VisualStudio.NET
Definición de Stack
• Estructura de datos que almacena
información en forma LIFO.
Top
• Operaciones:
Push
– Push
– Pop
– Top
– IsEmpty
IsEmpty?
Pop
Tests para un Stack
1.
2.
3.
4.
5.
6.
7.
8.
9.
Crear un Stack y ver que IsEmpty() es true.
Push un único elemento y verificar que IsEmpty() es
false.
Push un único elemento, luego Pop, y verificar que
IsEmpty() es true.
Push un único objeto, recordándolo, luego Pop y
verificar que ambos son iguales.
Push tres objetos, recordándolos y luego Pop, uno por
uno, verificando su igualdad y orden correcto.
Pop un Stack sin elementos.
Push un único elemento, usar Top y verificar IsEmpty es
false.
Push un elemento, recordándolo y luego usar Top y
verificar que es el mismo elemento.
Llamar a Top con un Stack vacío.
Conclusiones
•
How much of the intended code (Stack) is covered by one or
more tests?
Æ 100% Coverage
•
How much code was implemented in Stack.cs that didn’t serve
for the required functionality?
Æ None (Implement only what is needed)
•
How certain are we that the code works?
Æ 100%
•
If we need to change Stack’s implementation to use (for
example) a linked list, would it be easy to ensure we don’t break
current version?
Æ Yes!
•
If someone new needs to find out what the implemented class is
intended to do, how can he/she learn?
Æ Read unit tests. They serve as formal documentation.
(Therefore, store Unit Tests with the official code)
Extensiones de NUnit
• Existen extensiones de la herramienta,
orientados a ciertos modelos de aplicación
• Estas herramienta facilitan las pruebas
específicas, permitiendo un mayor nivel de
abstracción.
• Ejemplo: Win Forms, ASP, XML, etc.
Extensiones de NUnit
• NUnitASP y NUnitForms
– Periten realizar pruebas funcionales que
ejecutan acciones sobre la GUI.
– Proveen de clases helper para
• Ubicar controles en el form
• Analizar el contenido
• Disparar eventos.
Extensiones de NUnit
• Ejemplo NUnitForms (C#)
Form form = new Form();
form.Show();
ControlTester button = new ControlTester(“nombreBoton");
button.FireEvent("Click");
ControlTester textBox = new ControlTester(“nombreTxtBox");
textBox[“texto"] = “texto";
Assertion.AssertEquals("defaultText", textBox[“texto"];
Extensiones de NUnit
• Ejemplo NUnitASP (C#)
LabelTester label = new LabelTester(“label", WebForm);
LinkButtonTester link = new LinkButtonTester("linkBtn",
WebForm);
Browser.GetPage("http://localhost/ejemplo.aspx");
// Probar objetos de la página
link.Click();
AssertEquals(“un click", label.Text);
Visual Studio 2005
Visual Studio
Visual Studio
Visual Studio
Team Architect
Team Developer
Team Test
Application Modeling
Dynamic Code Analyzer
Load Testing
Logical Infra. Modeling
Static Code Analyzer
Manual Testing
Deployment Modeling
Code Profiler
Test Case Management
Unit Testing
Code Coverage
Class Modeling
Visio and UML Modeling
Team Foundation Client
Visual Studio Professional Edition
Visual Studio
Team Foundation
Change Management
Reporting
Integration Services
Work Item Tracking
Project Site
Project Management
Visual Studio Industry Partners
Process and Architecture Guidance
Visual Studio Team System
Temario
•
•
•
•
•
Testeo de aplicaciones
Desarrollo conducido por las pruebas
Impacto en el proceso de desarrollo
Herramientas para TDD
Buenas prácticas y recomendaciones
Buenas prácticas y recomendaciones
• Recomendaciones prácticas
– Pensar en todos los casos de prueba
necesarios; abordarlos uno a uno.
– Mantener los casos de prueba simples
– No confiar en un orden particular de ejecución
– No dejar efectos laterales luego de la prueba
– Si se encuentra un defecto, agregar el caso
que lo muestra primero, luego corregir
Buenas prácticas y recomendaciones
• ¿Se puede escribir la prueba después o
por un equipo independiente?
– Lo podría hacer un equipo independiente, pero
se pierde el feedback de las pruebas.
– Se puede codificar la prueba luego de
terminado el componente pero no se obtienen
los mismos beneficios.
– No sirve como prevención, ni como análisis del
problema.
Buenas prácticas y recomendaciones
• Automatización
– No intentar automatizar todo el proceso de
prueba, puede no ser viable ni práctico.
– La prueba debe ser estratégica en la búsqueda
de defectos.
– Utilizar distintos niveles y técnicas, los defectos
son evasivos.
Buenas prácticas y recomendaciones
• Prueba funcional vs. TDD
– Se ejecuta el software con el objetivo de encontrar
defectos, con la perspectiva del usuario.
– Prueba el sistema o divisiones funcionales como los
casos de uso, a través de la IU.
– Puede ser costosa de automatizar.
– La prueba funcional sigue siendo necesaria y es
una actividad complementaria al desarrollo
conducido por la prueba.
Resumen
Resumen
• TDD es una técnica para desarrollar
basado en las pruebas.
• TDD puede mejorar significativamente el
proceso de desarrollo.
• Existen herramientas que permiten llevarlo
a cabo en forma automática.
Referencias
•
James Newkirk; Test Driven Development in Microsoft .NET
•
Kent Beck; Test Driven Development, by example
•
Will Stott, James Newkirk; Test-Driven C#, Improve the Design and
Flexibility of Your Project with Extreme Programming Techniques
http://msdn.microsoft.com/msdnmag/issues/04/04/ExtremeProgrammi
ng
•
Visual Studio 2005 Team System
http://lab.msdn.microsoft.com/vs2005/teamsystem/
•
•
Herramientas www.nunit.org - www.junit.org – www.testdriven.net
Noticias, recursos www.testdriven.com
Descargar