tdd course (spanish)

188
TEST DRIVEN DEVELOPMENT IN ACTION ACCEPTANCE TEST DRIVEN DEVELOPMENT CONTINUOUS INTEGRATION Pedro Ballesteros Herranz <[email protected] > @pmbah

Upload: pedro-ballesteros

Post on 07-Jul-2015

496 views

Category:

Software


3 download

DESCRIPTION

Exercises: http://code.theprogrammingchronicles.com/tdd-exercises/#overview

TRANSCRIPT

Page 1: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT IN ACTIONACCEPTANCE TEST DRIVEN DEVELOPMENTCONTINUOUS INTEGRATION

Pedro Ballesteros Herranz <[email protected]>@pmbah

Page 2: TDD Course (Spanish)

“To turn you into test-infected developers”1

“To spread the TDD epidemic”

“Test-Driven Development is addictive”

OBJETIVOS DEL CURSO

1 Referencias

“tests-infected”: Termino ampliamente extendido para nombrar desarrolladores que hacen uso de tdd o unit testing (búscalo en google).

http://junit.sourceforge.net/doc/testinfected/testing.htm

JUnit in Action (Manning Publications) http://www.manning.com/tahchiev/

“The statistics show that people get easily “infected” with the unit-testing philosophy. Once you get accustomed to writing tests and see how good the feeling ofsomeone protecting you from possible mistakes is, you will wonder how was possible to live without unit-testing before.”

“Developers who adopt these techniques self-identify as "test-infected" meaning they are quite literally addicted to writing unit tests for their code which is something counter-intuitive to developers who have never experienced it.”

Page 3: TDD Course (Spanish)

OBJETIVOS DEL CURSO

Aprender la metodología TDD experimentándola de forma practica

Entender que implican los distintos tipos de tests Diferencias, cuando usar cada tipo, desarrolladores y testers.

¿Qué tests se pueden (o conviene) automatizar? ¿Qué esfuerzo suponen?

¿Qué tests se deben o no se deben utilizar desarrollando con TDD?

¿Sólo consiste en “hacer primero los tests”? NO…ES MUCHO MAS

Test-First Development vs Test-Driven Development

TDD tiene sus limites: como superarlos y cuanto cuesta.

Ventajas, beneficios, limites, inconvenientes, vulnerabilidades, mitos, malentendidos, etc.

Practicas, Ejercicios, Ejemplos, Practicas, Ejercicios, Ejemplos, …

Page 4: TDD Course (Spanish)

TEMARIO I

SOBRE LOS EJERCICIOS Y EJEMPLOS

INTRODUCCIÓN

INTRODUCCIÓN A EXTREME PROGRAMMING

CARACTERIZANDO TDD DESDE XP

INTRODUCCIÓN TDD Y ATDD

TEST UNITARIOS AUTOMATIZADOS

INTRODUCCIÓN CICLO DE DESARROLLO TDD

TEST DRIVEN DEVELOPMENT EXPLAINED

TIPOS DE TESTS

CICLO DE DESARROLLO DE TDD

PROPIEDADES FIRST DE LOS TESTS

PROPIEDADES SOLID PARA LA REFACTORIZACIÓN

Page 5: TDD Course (Spanish)

TEMARIO II

UNIT TESTING FRAMEWORKS

DUMMY / FAKE / STUB / MOCK / SPY

VALIDACIÓN POR ESTADO Y POR INTERACCIÓN

TDD APLICADO A ENTORNOS ESPECÍFICOS

ANTI-PATRONES Y MALAS PRÁCTICAS

ACCEPTANCE TEST DRIVEN DEVELOPMENT EXPLAINED

INTEGRACIÓN CONTINUA

TDD – OBJETIVOS, BENEFICIOS Y CARACTERÍSTICAS

TDD – VULNERABILIDADES Y PELIGROS

TDD – MITOS Y MALENTENDIDOS

COMO EMPEZAR CON TDD

Page 6: TDD Course (Spanish)

SOBRE LOS EJERCICIOS Y EJEMPLOS

Los ejercicios se han desarrollado enteramente aplicando la metodología TDD.

Los ejercicios están divididos a en secciones que representan avances de un solo paso del ciclo TDD (cada sección es una copia del paso anterior con un incremento adicional).

Algunas veces el avance de la solución representa la aplicación iterativa de varias iteraciones del ciclo TDD.

La impartición del curso está dirigida por ejemplos y prácticas de ejerciciosTDD, que representan el desarrollo de una aplicación empresarial completa,pasando por las capas de presentación, negocio y persistencia (aunquesigue tratándose de un ejemplo simplificado).

Algunas partes de la teoría en lugar de estar reflejadas en esta presentaciónestán exclusivamente incluidas en los ejercicios.

Page 7: TDD Course (Spanish)

SOBRE LOS EJERCICIOS Y EJEMPLOS

PRESENTACIÓN ACTUALDocumentación y referencia de la teoría del curso. Muchas diapositivas tienen notas asociadas a modo de apuntes de la teoría.

ENUNCIADO DE LA APLICACIÓN a desarrollarEnunciado detallado de la aplicación sobre la que girarán los ejercicios, con apuntes de la teoría a modo de recordatorio.

EJERCICIOS Y EJEMPLOSDisponibles en el repositorio de github: https://github.com/theprogrammingchronicles/tpc-tdd-exercises

DOCUMENTACIÓN DE EJERCICIOS Y EJEMPLOSTodos los ejercicios cuentan con documentación detallada de la problemática a resolver, teoría a revisar y pasos a realizar.El código fuente cuenta con JavaDocs descriptivos de la problemática propuesta en cada ejercicio y su resolución.Documentación de ejercicios en: http://code.theprogrammingchronicles.com/tpc-tdd-exercises/

MATERIAL DISPONIBLE

Page 8: TDD Course (Spanish)

SOBRE LOS EJERCICIOS Y EJEMPLOS

MUY IMPORTANTE

Este curso no pretende ser un compendio de recomendaciones sobre el uso de herramientas Javas aplicadas a TDD.

La teoría y práctica es completamente independiente de: Si se selecciona ant o maven como herramienta de build.

Si se selecciona Netbean, Eclipse, IntelliJ IDEA o UltraEdit como IDE.

Si se selecciona Hudson o Luntbuild como herramienta de CI.

Etc.

Lamentablemente no es posible la enseñanza práctica de TDD sin el apoyosobre un lenguaje de programación o tecnología concreta.

La parte práctica de este curso se ha desarrollado con Java, pero se haevitado la dependencia de frameworks muy específicos, la extrapolación dela práctica a otros lenguajes de programación debería ser sencilla(*).

TECNOLOGÍAS Y LENGUAJES

* La adaptación de este curso a otros lenguajes tan solo requeriría la migración de los ejercicios y ejemplos.

Page 9: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

INTRODUCCIÓN

Page 10: TDD Course (Spanish)

INTRODUCCIÓN

TDD nació como una de las prácticas de eXtreme Programming:

Actualmente ya es una metodología de desarrollo independiente.

Se está impartiendo como una metodología aislada de XP.

Ya se encuentra incluida como parte de otras metodologías más genéricas:

Rational Unified Process (RUP)

Agile Unified Process (AUP)

Open Unified Procress (Open UP)

SCRUM

Page 11: TDD Course (Spanish)

“Test-Driven Development es una Metodología de Desarrollo”

“NO es una metodología de testing”

“En primer lugar es una metodología de diseño y desarrollo, que como efecto lateral acaba proporcionando un código

completamente(*) probado por Unit Tests automatizados”

“La metodología proporciona un desarrollo del software a través de la aplicación iterativa, continua e incremental de tres pasos, de los cuales el

primero es siempre la codificación de un small scaled test”

INTRODUCCIÓN

(*) ¿Quiere eso decir que el sistema está probado al 100%?: NO, TDD no es un sustito de las técnicas de testing.

TDD no elimina la necesidad de otros tipos de tests. No elimina el trabajo de un grupo de testers o QA.

TDD si proporciona una barrera importante contra defectos.

El número de bugs detectados en tests de más alto nivel disminuye, el trabajo del grupo de QA disminuye.

Page 12: TDD Course (Spanish)

EXTREME PROGRAMMING

INTRODUCCIÓN A EXTREME PROGRAMMING

Page 13: TDD Course (Spanish)

INTRODUCCIÓN A EXTREME PROGRAMMING

http://www.extremeprogramming.org/

Guía rápida de eXtreme Programming con diagramas de flujo navegables.

http://www.xprogramming.com/

Información práctica de eXtreme Programming y TDD. Software, herramientas, librerías para multitud de lenguajes (xUnit, mocks, integración,…), entornos de desarrollo, etc.

Extreme Programming Explained: Embrace Change (2nd Ed), 2004, Kent Beck, Addison-Wesley Professional. Libro escrito por el creador de eXtreme Programming.

REFERENCIAS

Page 14: TDD Course (Spanish)

La metodología fue creada y utilizada inicialmente por Kent Beck en1996 (con ayuda de Ward Cunninghan y Ron Jeffires) en el proyectode nóminas C3 (Chrysler Comprehensive Compensation) de Daimler-Chrysler.

Tras terminar el proyecto, Beck escribió el libro ExtremeProgramming Explained, con el cual ganó el premio “SoftwareDevelopment Jolt Product Excelence Award”.

Desde entonces se ha ido refinando la metodología, y han idoapareciendo variantes (Ej. Remote eXtreme Programming).

INTRODUCCIÓN A EXTREME PROGRAMING

HISTORIA

Page 15: TDD Course (Spanish)

INTRODUCCIÓN A EXTREME PROGRAMMING

1968, Crisis del Software (conferencia de la OTAN sobre software). Los proyectos no terminaban en plazo.

Los proyectos no se ajustaban al presupuesto inicial. Baja calidad del software generado. Software que no cumplía las especificaciones.

Código inmantenible que dificultaba la gestión y evolución del proyecto.

Nace la “Ingeniería del Software”.

Construir software aplicando procesos de ingeniería.

Metodologías: Trabajos previos de construcción “sobre papel”: Análisis, Especificación,

Arquitectura, Diseño.

Esfuerzos invertidos en definir y fijar todo por adelantado y esfuerzos adicionales por controlar y contener el cambio.

MOTIVACIONES

Page 16: TDD Course (Spanish)

INTRODUCCIÓN A EXTREME PROGRAMMING

El panorama del software ha cambiado mucho desde 1968.

Ni se programa con tarjetas perforadas ni los ciclos de vida son tan largos.

Los procesos de ingeniería copiados de otras disciplinas no funcionan bien en el software.

No es sencillo tratar el software como la abstracción del mundo real.

El software es muy diferente a otras disciplinas.

Seguimos observando los mismos defectos. Los proyectos no terminan en plazo y no se ajustan al presupuesto inicial. El software no cumple especificaciones, es de baja calidad.

Seguimos encontrándonos con software inmantenible.

Los equipos de desarrollo acaban trabajando sin metodología.

MOTIVACIONES

¿Qué desarrollador cuenta con diagramas detallados de clase, de interacción o de estado antes de ponerse a codificar cada módulo?

Page 17: TDD Course (Spanish)

INTRODUCCIÓN A EXTREME PROGRAMMING

• Ausencia de metodología.

• Desarrolladores completamente autónomos y sin gestión externa.

• Hago lo que quiero y como quiero.

Extreme Programming NO ES “Cowboy Coding”.

• Trabajo a marchas forzadas.

• Estimaciones ajustadas y no realistas.

• Falta de documentación y conocimiento global del proyecto.

• Horas extras, fines de semana, vamos a meter más gente, ...

Extreme Programming NO ES “Death March Development”

LO QUE NO ES

“Con Extreme Programming se trabaja a un ritmo sostenible” (sustainable pace, las famosas 8h)

Page 18: TDD Course (Spanish)

“Es una metodología ágil de desarrollo de software que pone más énfasis en la adaptabilidad que en la previsibilidad”

INTRODUCCIÓN A EXTREME PROGRAMMINGLO QUE SI ES

¿Y POR QUÉ EXTREME?

“Los elementos beneficiosos de las metodologías tradicionales de ingeniería del software se llevan a niveles extremos”

Extreme Programming abraza el cambio,en lugar de intentar contenerlo.

Page 19: TDD Course (Spanish)

INTRODUCCIÓN A EXTREME PROGRAMMING

Adaptarse a los cambios en cualquier punto de vida del proyecto. En lugar de esfuerzos para fijar todo desde el principio y luego controlarlo.

Adoptar las mejores prácticas de desarrollo aplicándolas dinámicamente durante el ciclo de vida del software.

Mejorar la calidad del software, la productividad y el tiempo de respuesta a cambios de requisitos por el cliente.

OBJETIVOS DE LA METODOLOGÍA

“Los cambios de requisitos sobre la marcha son un aspecto natural, inevitable e incluso deseable

del desarrollo de proyectos de software”

Page 20: TDD Course (Spanish)

INTRODUCCIÓN A EXTREME PROGRAMMING

Activities

Values

Principles

Practices or Rules

COMPONENTES DE LA METODOLOGÍA

Page 21: TDD Course (Spanish)

INTRODUCCIÓN A EXTREME PROGRAMMING

Coding

Testing

Listening

Designing

ACTIVITIES

Page 22: TDD Course (Spanish)

INTRODUCCIÓN A EXTREME PROGRAMMING

Simplicity

Communication

Feedback

Respect

Courage

VALUES

Page 23: TDD Course (Spanish)

INTRODUCCIÓN A EXTREME PROGRAMMING

Rapid Feedback

Assume Simplicity

Incremental Change

Embracing Change

Quality Work

PRINCIPLES

Page 24: TDD Course (Spanish)

INTRODUCCIÓN A EXTREME PROGRAMMING

• User Stories: User stories are written.

• Release Plan: Release planning creates the release schedule.

• Release Often: Make frequent small releases.

• Iterative: The project is divided into iterations.

• Iteration Planning: Iteration planning starts each iteration.

Planning

• Optimize Last: Give the team a dedicated open work space.

• Steady Pace: Set a sustainable pace.

• Stand-up Meeting: A stand up meeting starts each day.

• Project Velocity: The Project Velocity is measured.

• Move people around.

• Fix XP when it breaks.

Managing

PRACTICES OR RULES

Page 25: TDD Course (Spanish)

INTRODUCCIÓN A EXTREME PROGRAMMING

• Simplicity•System Metaphor: Choose a system metaphor.

•CRC cards: Use CRC cards for design sessions.

•Spike Solution: Create spike solutions to reduce risk.

• Nothing Early: No functionality is added early.

• Refactor: whenever and wherever possible.

Designing

•Customer On-Site: The customer is always available.

• Coding Standard: Code must be written to agreed standards.

• Test Driven Development: Code the unit test first.

•Pair Programming: All production code is pair programmed.

•Serial Integration: Only one pair integrates code at a time.

• Continuous Integration: Integrate often.

•Continuous Integration: Set up a dedicated integration computer.

• Collective Ownership: Use collective ownership.

Coding

PRACTICES OR RULES

Page 26: TDD Course (Spanish)

INTRODUCCIÓN A EXTREME PROGRAMMING

• Unit Tests: All code must have unit tests.

• Unit Tests: All code must pass all unit tests before it can be released.

• Bug Tests: When a bug is found tests are created.

• Acceptance Tests: Acceptance tests are run often and the score is published.

Testing

PRACTICES OR RULES

Test-Driven Development está incluido en el área de “coding”, no de “testing”

Page 27: TDD Course (Spanish)

CODING

“Without code, there is no work product”

SIMPLICITY

“Keep it simple, stupid” (KISS)

“You ain’t gonna needed it” (YAGNI)

TESTING

“If it's worth building, it's worth testing. If it's not worth testing, why are you wasting your time working on it?”

DESIGNING

“Using Test Driven Development – Refactoring”

MANAGING AND PLANNING

“SCRUM”

CARACTERIZANDO TDD DESDE XP

Page 28: TDD Course (Spanish)

CARACTERIZANDO TDD DESDE XP

CODING El único artefacto realmente importante es el código funcionando.

Las instrucciones que el ordenador interpreta.

El código claro y simple es la mejor fuente de documentación. Para comprender, transmitir, explicar, evaluar y discutir una solución. Es claro y conciso, se interpreta de solo una forma.

Código colectivo (acabar con “solo lo puede tocar el que lo hizo”).

SIMPLICITY Codificar solo lo que realmente se necesita, lo que el cliente está pidiendo.

Se programa para el “ahora” y nunca para el “futuro” (*)

No se pierde tiempo anticipando el diseño de grandes frameworks o librerías. Nunca se escribe una línea de código pensando en el “por si acaso luego se

necesita” (al final no se necesitará).

Test-Driven Development será la herramienta de diseño. El framework, las librerías y el código reutilizable aparecerán de forma orgánica. Justo cuando se requieren y con un diseño modular y flexible al cambio.

Page 29: TDD Course (Spanish)

CARACTERIZANDO TDD DESDE XP

TESTING Tests unitarios utilizados para crear arquitectura, diseñar y codificar.

Tests de sistema o integración para aumentar y mantener la calidad. Extreme: Si un poco de testing elimina defectos, mucho testing eliminará mas. Los defectos, bugs, o errores son parte inherente del desarrollo de software. Tantos tests como se puedan pensar, tantos como puedan romper el código, si

todos los tests se pasan el desarrollo se ha terminado.

UNIT TESTS: DOCUMENTACIÓN Una librería con documentación se entiende bien, pero si incluye ejemplos

se entiende mucho mejor: Los tests unitarios son ejemplos de cómo se usa nuestro código.

No sustituyen toda la documentación pero son una parte importante.

ACCEPTANCE TESTS: Especificación de requisitos ejecutable Verificar que los desarrolladores han entendido los requisitos tal y como los

quiere el cliente.

Ayudar al cliente a entenderse a si mismo.

Controlar el estado de avance del sistema.

Page 30: TDD Course (Spanish)

CARACTERIZANDO TDD DESDE XP

DESIGNING

Diseños simples, claros, modulares y desacoplados.

Los módulos se mantienen inalterados si se modifican las dependencias.

Se diseña programando, mediante el refactoring usado en TDD.

TDD es el motor de diseño: simple, claro, modular, desacoplado, flexible a cambios y con mínimos defectos.

PLANNING & MANAGING SCRUM: Ya estamos aplicando todos los principios XP de gestión y

planificación de los proyectos.

Page 31: TDD Course (Spanish)

Codificar para el “ahora” y nunca para el “futuro”, aunque parezcacontraproducente, es clave tanto en Extreme Programming como enTest Driven Development.(*)

Y a su vez Test-Driven Development es clave para poder programar elahora y evolucionar hacia el futuro sin dificultades.

La programación TDD permite evolucionar el producto “sin dolor”,hacia lo que quiere el cliente y hacia arquitecturas robustas, flexiblesy de calidad (refactorización).

FUNDAMENTAL EN TDD (Y XP)

“Evitar la anticipación NO SIGNIFICA crear spaghetti code(*)”·

Ahora tenemos una metodología que nos permite obtener buenosdiseños mediante la codificación directa. Diseñamos a través de unacodificación que esta guiada y protegida por los tests.

YAGNI: “YOU AIN’T GONNA NEEDED IT”

Page 32: TDD Course (Spanish)

Acceptance Test Driven Development

TEST DRIVEN DEVELOPMENT

Test-First Development

+Refactoring

Test-Driven Development

=PRIMER VISTAZO GENERAL

Page 33: TDD Course (Spanish)

¿En serio tenemos esa tradición?

¿Cuántos habéis trabajado alguna vez en un proyecto en el que se programen tests?

¿Cuántos participáis en algún proyecto en el que se programen activamente los tests?

¿Qué tipos de tests y con que resultados?

TEST AFTER DEVELOPMENT

TRADICIONALMENTE SE HAN CODIFICADO LOS TESTSDESPUÉS DE LA FUNCIONALIDAD

Page 34: TDD Course (Spanish)

AUTOMATED UNIT TESTSLOS TESTS SE TIENEN PROGRAMAR

¡¿QUEEE?!¿PROGRAMAR TESTS?

¿NO QUERÍAMOS SER AGILES?¡TARDAREMOS EL DOBLE!

Page 35: TDD Course (Spanish)

Una tarea terminada en 1 semana

Hemos preparado la bomba de relojería

Nada Funciona Realmente3 semanas corrigiendo errores

¿Seguro? ¿O sólo hemos creado la falsa sensación

de la tarea se ha terminado?¿Qué hemos conseguido?

Decir: ¡Ya está! ¡Y en una semana!

“¿Hemos tardado realmente una semanas?”“¿Habríamos tardado más codificando pruebas unitarias?”

AUTOMATED UNIT TESTSUN ESCENARIO HABITUAL

“NO programar tests SI añade trabajo extra”“Y usando TDD obtendremos los tests unitarios de forma casi

orgánica, a la vez que dirigen el desarrollo de la lógica funcional”

Page 36: TDD Course (Spanish)

AUTOMATED UNIT TESTS

Actualmente todo desarrollador ya realiza pruebas unitarias(*)

¿Qué tipos de pruebas unitarias estamos haciendo?

YA HACEMOS PRUEBAS UNITARIAS

PRUEBAS UNITARIASMANUALES Y VISUALES

(*) O esperamos que al menos esto sea cierto.

Page 37: TDD Course (Spanish)

VISUAL UNIT TESTS

REQUIEREN ESFUERZO Y TIEMPO ADICIONAL

¿Hemos ejercitado cada línea de código con el depurador antes de decir que está terminado?

¿Seguro?

¿Cómo podría estarlo? - depurando otra vez.

DEPURACIÓN LÍNEA A LÍNEA

Page 38: TDD Course (Spanish)

VISUAL UNIT TESTS

REQUIEREN ESFUERZO Y TIEMPO ADICIONAL

¿Aseguran las trazas que he ejercitado todo el código?

¿He revisado todas las trazas sin perder ninguna antes de decir que está terminado?

¿Seguro? ¿Cómo podría estarlo? – Traceando otra vez

VERIFICACIÓN VISUAL DE TRAZAS

Page 39: TDD Course (Spanish)

VISUAL UNIT TESTS

Orientadas al establecimiento de pre-condiciones y pos-condiciones en depuración.

No orientadas al Unit Testing.

Se deben activar antes de ejecutar la aplicación.

Detienen la ejecución del sistema ante el primer fallo.

REQUIEREN ESFUERZO Y TIEMPO ADICIONAL

ASSERTS EN EL CÓDIGO FUNCIONAL

Page 40: TDD Course (Spanish)

VISUAL UNIT TESTS

¿Estamos seguros que todos hacen pruebas visuales y que se hacen bien? Las programación de pruebas unitarias elimina esa incertidumbre.

Repetir las pruebas unitarias programadas es hacer un sólo clic.

Repetir las pruebas visuales es volver a pasar todo el proceso manual que supone.

Los tests visuales son propensos a fallos y descuidos.

El ojo tiene que localizar los errores.

Mantenimiento: el resto de desarrolladores no sabrán qué probar, ni cómo.

Ausencia de pruebas de regresión: al modificar una funcionalidad ¿seguirá funcionando el resto?

¿No sería mejor dedicar este mismo tiempo a su automatización?

No obstante veremos que usando TDD ese tiempo se optimiza y sefunde de forma natural con la codificación de funcionalidad, pero:

REQUIEREN ESFUERZO Y TIEMPO ADICIONAL

Page 41: TDD Course (Spanish)

AUTOMATED UNIT TESTS

En el panorama Java Open Source prácticamente todos los proyectos tienen Unit Tests completos.

Entiendo que en muchas otras tecnologías se da el mismo caso.

Algunos ejemplos: (*)

Tomcat

Glassfish (también usan integración continua con Hudson)

Spring Framework

Funambol SyncML Server

¿SE ESTÁN USANDO?

(*) Desconozco si usan TDD. Todos estos proyectos tienen código de tests. Los desarrolladores están obligados a incluirlos.(*) Antes de seguir: Exercise 1 – My First Unit Test.

Page 42: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

VEAMOS TEST DRIVEN DEVELOPMENT EN ACCIÓN

BUENO, YA BASTA DE BONDADES Y PROMESAS

Page 43: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

http://www.agiledata.org/essays/tdd.html Buena introducción de TDD.

Clean Code: A Handbook of Agile Software Craftsmanship, 2008, Robert C. Martin Imprescindible

The Clean Coder: A Code of Conduct for Professional Programmers, 2011, Robert C. Martin

Diseño Ágil con TDD, 2010, Carlos Blé Jurado

Test Driven Development: By Example, 2003, Kent Beck Del creador de Extreme Programming y Test Driven Development.

Test-Driven Development: A Practical Guide, 2003, David Astels

http://www.xprogramming.com/software Software, herramientas, librerías para multitud de lenguajes (xUnit, mocks, integración,…), entornos de

desarrollo, etc.

REFERENCIAS

Page 44: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENTPRIMER VISTAZO AL CICLO ITERATIVO DE TDD

One Small Scaled Test

Cada iteración no más de diez modificaciones en el código.

Diez líneas de código nuevas.

Diez correcciones en código existente.

Diez modificaciones para refactorizar.

Page 45: TDD Course (Spanish)

CODIFICAR UN TEST NO se codifican todos los posibles tests por adelantado.

Se codifica un solo test de una funcionalidad (small scaled test) Ej: Si un solo método requiere N tests, se itera de forma completa el ciclo TDD

uno por uno.

Son ejemplos de uso o clientes del código funcional.

Cada iteración completa debe suponer un incremento a pequeña escala, de unas diez modificaciones (líneas nuevas, actualización de la existentes, etc.).

¿COMO SE CODIFICA EL TEST? Debe cumplir las propiedades F.I.R.S.T

Si tardo dos minutos en una iteración (algo normal), habré ejecutado los tests240 veces en un solo día.

Small Scaled Test: Test Unitario Aislado o Test de Integración de Lógica.

Obtener los tests: ¿Qué probaría si tengo que depurar?.

Obtener los tests: Aceptance Test Driven Development (el interruptor que arranca el motor TDD).

PRIMER VISTAZO AL CICLO ITERATIVO DE TDD

(*) Exercise 1.4 – Test Code Coverage

TEST DRIVEN DEVELOPMENT

Page 46: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

EJECUTAR EL TEST

MUY IMPORTANTE: Se debe ejecutar antes de codificar la funcionalidad.

Probamos que realmente falla. Si no falla revisamos si el test es correcto.

No saltarse nunca este paso: que se tiende a olvidar.

Aunque en la primera iteración el código ni siquiera compilará, en las siguientes iteraciones no será así.

Seguimos refinando código que ya funciona.

Se ha codificado la funcionalidad que arregla el test anterior.

Implementamos el siguiente test este código que ya funciona y comprobamos que el test falla para asegurar que se ha implementado bien.

CODIFICACIÓN Y EJECUCIÓN (SUBITERACIONES)

Se codifica la funcionalidad hasta que el test funciona.

PRIMER VISTAZO AL CICLO ITERATIVO DE TDD

“If the light is green, the code is clean” *JUnit slogan.

Page 47: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

CODIFICANDO LA FUNCIONALIDAD

MUY IMPORTANTE: Se codifican única y exclusivamente las líneas que hacen pasar el test (al desarrollador le cuesta acostumbrarse).

No debemos codificar algo por si acaso luego se usa (“nunca se usará”).

No debemos entretenernos en diseñar y codificar un framework inicial (“al final habrá que cambiarlo”).

Arquitecturas, diseños, frameworks, librerías: aparecerán de forma natural.

“The only thing that really matters in software development is working code”

You ain’t gonna needed it” (YAGNI)

“Keep it simple, stupid” (KISS)

“If it's worth building, it's worth testing. If it's not worth testing, why are you wasting your time working on it?”

PRIMER VISTAZO AL CICLO ITERATIVO DE TDD

Page 48: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

CODIFICACIÓN Y REFACTORIZACIÓN (SUBITERACIONES) Refactorizar comprobando que no se rompe el test que ya funcionaba.

FUNDAMENTAL: No se deja la factorización para el futuro, para momentos de baja carga de trabajo (“esos momentos no existen”).

Seguramente es el paso más importante de TDD

Refactorización después de cada pequeña iteración (constantemente).

La refactorización se aplica principalmente para: Eliminar código repetido: No hay mayor aberración que la codificación “Copy &

Paste”, que multiplica los esfuerzos de mantenimiento. Extraer código reutilizable (XP: fijar estándares(*) en el grupo de desarrollo)

Refactorizamos guiándonos por los principios S.O.L.I.D.

SIN REFACTORIZACIÓN NO HAY METODOLOGÍA

SIN REFACTORIZACIÓN NO EXISTE TEST DRIVEN DEVELOPMENT

(sólo sería una forma de Test First Development)

(*) Estandarizar la reutilización: ver notas diapositiva

Page 49: TDD Course (Spanish)

ACCEPTANCE TEST DRIVEN DEVELOPMENT

El cliente averigua como quiere realmente su sistema.

Se hace consciente de la casuística que tienen los casos de uso.

Los desarrolladores entienden lo que quiere el cliente.

El cliente ha visto toda la casuística y el desarrollador sabe como quiere que se resuelva cada variante.

Se codifican: Especificación de Requesitos Ejecutable.

PRIMER VISTAZO

“Se podría decir que ATDD es una metodología de especificación de requisitos antes que una metodología de testing”

Page 50: TDD Course (Spanish)

ACCEPTANCE TEST DRIVEN DEVELOPMENT

El cliente tiene feedback del avance del desarrollo mediante las pruebas de aceptación.

También llamadas “Pruebas de Cliente”: Asusta el compromiso de aceptar el producto sin condiciones si se pasan los tests.

La especificación de requisitos ya no se escribe como un redacción o “novela” de la funcionalidad.

User Stories (criterios de aceptación) descritos con ejemplos (tests)

El User Story equivale al título de un caso de uso tradicional.

El User Story se describe con un conjunto de ejemplos concretos y directos.

Se debe utilizar el vocabulario del negocio, y no de la implementación.

Se obtienen mediante colaboración del Analista del Negocio y el ProductOwner (o cliente), y si es posible con la participación de los desarrolladores.

PRIMER VISTAZO

Ejercicio 2: Starting Test Driven Development

VOLVEREMOS CON ATTD MAS ADELANTE

Page 51: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

TEST DRIVEN DEVELOPMENT EXPLAINED

Page 52: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

Test Driven Development es principalmente una metodología dedesarrollo de software

La misión principal de TDD es dirigir la arquitectura, el diseño y lacodificación del software.

El efecto colateral es que se termina obteniendo una bateríacompleta de tests unitarios* y por tanto un software con pocos fallos.

TDD no remplaza métodos tradicionales de testing, sigue siendonecesario el testing en niveles superiores (pero con menos bugs).

INTRODUCCIÓN

* Veremos que los tests unitarios no son suficientes para validar un sistema.

Page 53: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

“The act of writing a unit test is more an act of design than of verification. It isalso more an act of documentation than of verification. The act of writing a unittest closes a remarkable number of feedback loops, the least of which is the onepertaining to verification of function”

INTRODUCCIÓN

* Extreme Programming in Practice, Agile Software Development, y muchos libros más.

Robert C. Martin*

Page 54: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

Kent Beck, 2003

Un sistema Smalltalk, usando TDD, en un proyecto de 4 años, 40 personas/año.Resultando en 250.000 líneas de código funcional y 250.000 líneas de código detest. Se consiguieron 4000 tests ejecutándose en 20 minutos(*), con el sistemacompleto corriendo varias veces al día.

Y existen testimonios similares de otros grandes proyectos.

ESCALABILIDAD

SENCILLAMENTE… NO ES CIERTO

Se oye decir que las metodologías Agile sólo son válidas para pequeños proyectosde un puñado de personas durante unos pocos meses, que no funcionan enproyectos “reales” y más largos.

* Se refiere a grupo completo de test conseguidos, no los small scaled test usados en el día a día del desarrollo.

“It is clear that TDD works for good-sized systems”

Page 55: TDD Course (Spanish)

APLICANDO TESTS AL DESARROLLO

TEST DRIVEN DEVELOPMENT (TDD)

• Grupos dedicados a la programación de los tests.

• Los desarrollos no tienen en cuenta la testeabilidad del diseño y el código funcional.

• Util para la validación, verificación y detección de bugs, no para dirigir desarrollos.

• Produce menor cobertura de código testeado.

• Peligro de abandono de tests: no se mantienen, quedan obsoletos y se desactivan.

TEST FIRST DEVELOPMENT (TFD)

• Ciertos tests son difíciles de programar por adelantado.

• Normalmente para tests muy alejados del código (sistema, integración, aceptación, etc.).

• Más util para la detección de fallos que para dirigir los desarrollos (arquitecturas iniciales).

• Peligro de abandonar los tests: distan del código, son más frágiles y requieren mayor mantenimiento.

• Peligro de programar tests inútiles: El desarrollo posterior introduce cambios de diseño que invalidan los tests.

TEST AFTER DRIVEN DEVELOPMENT (TAD)

• Los tests son programados por los desarrolladores de la funcionalidad.

• Están al mismo nivel que el código.

• Produce un diseño y un código adaptado completamente al unit testing.

• Dirige los desarrollos y proporciona cobertura completa de “tests unitarios”.

• Los tests son parte del desarrollo de la funcionalidad: no se abandonan.

• Programación en incrementos muy reducidos (small scaled tests).

• Siguen siendo necesarios tests de más alto nivel para validar completamente el sistema.

Page 56: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

Sólo se implementa la funcionalidad necesaria, programando siempre el “ahora” y nunca el “mañana” (YAGNI).

Dirigir desde el código la arquitectura, diseño y codificación.

Minimizar el número de defectos que llegan a los tests de más alto nivel o a la plataforma de producción.

Producir software modular, altamente reutilizable y preparado para el cambio.

FUNDAMENTOS Y OBJETIVOS

“El desarrollador asume roles de arquitecto, diseñador y programador”

La implementación de pequeños ejemplos en iteraciones constantes haceemerger la arquitectura que se necesita.

Y se produce una arquitectura, diseño y código que emerge de la noambigüedad de los tests automatizados.

Page 57: TDD Course (Spanish)

TIPOS DE TESTSALCANCE FINALIDAD

VISIBILIDAD

TESTS DE SISTEMA

TESTS DE INTEGRACIÓN

TESTS UNITARIOS

TESTS DE ACEPTACIÓN

TESTS NO FUNCIONALES

RENDIMIENTO STRESS

CARGA . . .

TESTS FUNCIONALES

TESTS DE INTERFAZ DE USUARIO

TEST DE CAJA BLANCA

TEST DE CAJA NEGRA

Definiendo un vocabulario común

Test visuales o programados.

Dificultades para su automatización.

¿Es viable e incluso recomendable la automatización de todos los tipos?.

Page 58: TDD Course (Spanish)

ALCANCE DE LOS TESTS

TESTS DE SISTEMA

Ejercitan el sistema desde los extremos (end-to-end).

Entran por la interfaz del usuario final y llegan hasta el extremo opuesto.

Ej. desde la Web hasta la Base de Datos.

Se ejecutan en la plataforma de pre-producción.

TESTS DE INTEGRACIÓN Ejercitan varias unidades del sistema de forma conjunta, verificando la

correcta colaboración entre dependencias.

Se ejecutan en la plataforma de pre-producción.

Aunque son aceptables otros entornos según las intenciones de las pruebas.

Múltiples combinaciones según las colaboraciones implicadas.

La frontera que transforma test unitarios en integración a veces es difusa.

Algunos test de integración se pueden usar en las iteraciones TDD (test de integración a pequeña escala).

Page 59: TDD Course (Spanish)

ALCANCE DE LOS TESTS

TESTS UNITARIOS

Ejercitan una unidad de código de forma aislada.

Un test = un caso o ejemplo de uso de un método o función.

Se compilan y se enlazan con el código funcional.

Se ejecutan en el equipo de cada desarrollador.

También periódicamente en entornos de desarrollo con herramientas de integración continua.

Pertenecen a los desarrolladores (usando TDD no hay otra opción).

A veces no es claro cual debería ser el nivel de aislamiento.

Page 60: TDD Course (Spanish)

FINALIDAD DE LOS TESTS

TEST DE ACEPTACIÓN O DE CLIENTE Verifican que el software cumple con los requisitos de negocio.

Pertenecen al Product Owner o Cliente. Definidos en el Sprint Planning (ATDD: Discusión y Destilación) Todo el equipo (desarrolladores y testers incluidos) Al menos el Product Owner ayudado por el analista del negocio.

Tests Funcionales y No Funcionales.

Son “Tests de Sistema”(*) ejecutados en entorno de pre-producción.

Ayudan al cliente a entenderse y a los desarrolladores a entender al cliente.

Seguimiento del grado de avance: Especificación de Requisitos Ejecutable

TESTS DE CERTIFICACIÓN(**)

Los Tests de Aceptación son parecidos a los tests de certificación definidospor un grupo de QA. En ATDD se usan como Tests de Cliente queproporcionan un Mecanismo de Especificación de Requisitos.

* No suelen entrar por la IU, pero se suelen considerar tests de sistema.** Certificación: ver notas.

Page 61: TDD Course (Spanish)

FINALIDAD DE LOS TESTS

TEST DE INTERFAZ DE USUARIO Verifican la interfaz de los usuarios finales a todos los niveles.

Son test de sistema, ejecutados en entorno de pre-producción. Aspecto, usabilidad, interactividad, interacción H-M, flujo, textos, faltas de ortografía, ausencia

de fallos, tiempos de respuesta, legislación (ej. accesibilidad de la web, LSSICE), etc.

TEST DE ACEPTACIÓN vs INTERFAZ DE USUARIO Los tests de aceptación no tienen por qué ejercitar la UI.

Validan la lógica de negocio o funcionalidad del sistema. Verifican QUÉ hace el sistema, NO CÓMO se usa.

Dirigir los desarrollos mediante test de UI puede producir una arquitectura o diseño demasiado acoplado a una UI específica. La funcionalidad debería ser completamente independiente de la UI. Permitir el cambio de la UI o tener varias UI sin afectar a tests de aceptación. La conexión entre la lógica y la UI debería provocar pocos fallos si se ha

conseguido una buena cobertura de tests unitarios o de integración.

Incluir los tests de UI como tests de aceptación si es requisito de negocio.

Page 62: TDD Course (Spanish)

FINALIDAD DE LOS TESTS

TESTS FUNCIONALES

Tests de aceptación que verifican los requisitos funcionales.

Son tests de sistema ejecutados en entorno de pre-producción.

TESTS NO FUNCIONALES Tests de aceptación que verifican requisitos no funcionales.

Existen varios tipos de tests no funcionales:

Carga, stress, rendimiento (ej. número de altas por minuto), tolerancia a fallos (HA, High availability), etc.

Los puede definir un grupo de QA encargado de asegurar los requisitos mínimos de calidad de toda la organización.

El cliente puede imponer sus propios requisitos no funcionales.

Page 63: TDD Course (Spanish)

TIPOS DE TESTS

Aceptación

Sistema UI

IntegraciónUnitario

Unitario

Integración

Page 64: TDD Course (Spanish)

TEST UTILIZADOS EN TDD

TESTS DE INTERFAZ

DE USUARIO

TESTSFUNCIONALES

TESTS NO FUNCIONALES

TESTS DE INTEGRACIÓN

TESTSUNITARIOS

CODIFICAR

TEST DE SISTEMA O INTEGRACIÓN

¿Cuántos tests habría que codificar antes de la funcionalidad?

Habría que codificar innumerables tests antes de escribir una sola línea de código funcional.

Existen multitud de combinaciones de integración (qué con qué).

Extreme Programming precisamente quiere reducir la carga de trabajos previos, buscando la inmediatez.

LO QUE NO ES TDD

¡Uf!¿Repetir todo por cada iteración?

* Ver notas

Page 65: TDD Course (Spanish)

TEST UTILIZADOS EN TDD

Se deciden los tests a realizar ATDD: deciden siguiente funcionalidad. Entrada de

datos del bucle TDD.

Grupo de QA: Certificación, test que aseguran la calidad de los productos.

Visuales, automáticos, antes, después, etc.

Valorar recursos y esfuerzos de mantenimiento.

TESTS DE ACEPTACIÓN (ATDD)

NO FUNCIONALESFUNCIONALES

SPRINT PLANNING: Planificar Tests

Desarrollo Incremental (minuto a minuto)

Todos utilizan TDD para los desarrollos.

Small Scaled Test: Se van desgranando tests de aceptación en test unitarios o de integración.

Los tests se mantienen y se desarrollan de forma paralela a la funcionalidad.

Los tests dirigen el desarrollo y las siguientes iteraciones deciden nuevos tests.

* Ver notas

INTEGRACIÓN

INTERFAZ DE USUARIO

SISTEMA

CARGA

DEVELOPMENT: Desarrollar con TDD

Page 66: TDD Course (Spanish)

DISTRIBUCIÓN DE LOS TESTS

Invertir más esfuerzos en test de alto nivel y dejarel código con pocos o ningún test unitario.

TRADITIONAL TESTING PYRAMID

UNITTESTS

INTEGRATIONTESTS

SYSTEM, GUI, ACCEPTANCE TESTS

PIRÁMIDE INESTABLE

Los test de alto nivel pesan demasiado, la pirámide se desmorona fácilmente.

La mayor carga está en los test más frágiles y más dependientes del entorno.

Esta aproximación que requiere esfuerzos específicos de desarrollo y mantenimiento.

Los tests quedan obsoletos fácilmente y se corre el riesgo de abandonarlos.

Page 67: TDD Course (Spanish)

DISTRIBUCIÓN DE LOS TESTS

Automated tests were considered expensive to write and were often written months, orin some cases years, after a feature had been programmed.

One reason teams found it difficult to write tests sooner was because they wereautomating at the wrong level.

An effective test automation strategy calls for automating tests at three differentlevels, as shown in the figure, which depicts the test automation pyramid.

MIKE COHN’S TESTING PYRAMID

Small in number

At least one per story

Loads of them, per method

•Mike Cohn. Uno de los fundadores de la Scrum Alliance. Profesor en el first Certified ScrumMaster course,. Varios libros publicados sobre Agile.* http://blog.mountaingoatsoftware.com/the-forgotten-layer-of-the-test-automation-pyramid•http://www.scrumalliance.org/

(Test de UI y de Sistema)GUI TESTS

ACCEPTANCE TESTS

UNIT TESTS

(Test Funcionales, No Funcionales, Integración y Sistema)

(Test Unitarios Aislados, Test de Integración de Pequeña Escala)

SE INTENTA EVITAR EXCESIVA REDUNDANCIA DE TESTS

Page 68: TDD Course (Spanish)

PROPIETARIOS DE LOS TESTS

PRODUCT OWNERPRODUCT MANAGER

SCRUM MASTER

• Aceptación o Cliente• Interfaz de Usuario

• Funcionales

• No Funcionales

DEVELOPER GROUP

• Desarrolla con TDD

• Unitarios

• Integración

QA GROUP

• Sistema

• Interfaz de Usuario

• Certificación

• Calidad

• Funcionales

• No Funcionales

Page 69: TDD Course (Spanish)

RUNNING TDD

Cada iteración del bucle un incremento muy reducido.

Unas 10 modificaciones (del código) en cada iteración.

Objetivo: avanzar de forma paralela tests y funcionalidad.

No todos los tests por adelantado (si no en incrementos)

RAPID FEEDBACK

La pequeña escala de las iteraciones permite tomar decisiones dediseño y arquitectura lo antes posible para aplicarlas durante larefactorización.

ITERATIVO E INCREMENTAL

Page 70: TDD Course (Spanish)

RUNNING TDD

Seleccionar un test de aceptación

Incrementalmente se descompone en “Small Scaled Tests” Test Unitarios Aislados o Tests de Integración de Pequeña Escala.

Elaboramos nuestro propio “Unit Test Backlog” Nuestra lista informal de tests para las N siguientes iteraciones.

Small Scaled Test

Término extraído de “Test Driven Development: By Example “, Kent Beck.

Recomendable utilizar Tests Unitarios Aislados.

En ocasiones más sencillo no aislar ciertas partes. Realizar el test unitario con las dependencias reales (integración de pequeña escala).

Valorar en función de cuánto nos alejamos de las propiedades F.I.R.S.T

Tests que deben cumplir las propiedades F.I.R.S.T (test unitarios).

1 - ADD A TEST

Page 71: TDD Course (Spanish)

F.I.R.S.T

FAST

INDEPENDENT

REPEATABLE

SMALL

TRANSPARENT

Son propiedades que deben cumplir los tests utilizados en el bucle TDD, y que noaplican a otros tipos de test como los test de integración y los test de sistema.

Page 72: TDD Course (Spanish)

F.I.R.S.T

Cada test unitario se debe ejecutar en milésimas de segundo.

Se ejecutan mientras desarrollamos en pequeños incrementos.

2 minutos por iteración: 240 ejecuciones en 8 horas.

Los tests de integración (o alto nivel) son demasiado lentos.

Hay que lanzar todos los test del modulo o unidad en desarrollo. Si se vuelven lentos: separar las baterías de test.

Tests usados en el desarrollo y lanzados en cada iteración.

Tests a largo plazo (antes de un commit o integración).

Los “Tests Runners” pueden lanzar tests de una sola clase o un solo método.

Existen IDEs o plugins que ejecutan los tests automáticamente mientras estamos codificando.

Cuanto más veloz mejor: el test es lo que nos permite avanzar.

FAST

Page 73: TDD Course (Spanish)

F.I.R.S.T

Cada test unitario completamente independiente del resto de tests.

Nunca predeterminar un orden en la secuencia de tests unitarios.

Un test es una unidad muy pequeña.

Ej: un método de una clase de test de xUnit.

Cada método de test se debe ejecutar independiente del resto.

Las librerías tipo xUnit fomentan la independencia de los tests.

No deben depender de configuraciones de despliegue.

No depender del acceso a una base de datos concreta.

No depender de datos existentes.

No depender de acceso a máquinas remotas concretas.

Debe ser posible su ejecución en cualquier máquina en cualquier estado.

INDEPENDENT

* Los test de más alto nivel que no se usan en TDD no tienen por qué cumplir estas propiedades. Por ejemplo un test de IU que necesita probar una secuencia predeterminada del flujo de eventos, o tests de una máquina de estados.

Page 74: TDD Course (Spanish)

F.I.R.S.T

Un test unitario debe ser inocuo.

No debe alterar el sistema.

Debe comportarse como si nunca se hubiera ejecutado. No alterar datos de producción, no enviar emails, mensajes, etc.

Debe producir siempre el mismo resultado.

REPEATABLE

Page 75: TDD Course (Spanish)

F.I.R.S.T

Probar la mínima cantidad de funcionalidad posible.

Deben ser atómicos, probar lo indivisible.

Prueban un solo caso de un método de una clase.

Permitir localizar más rápidamente los defectos.

Evitar el tener que usar el depurador para encontrar la causa del fallo.

Idealmente cada test debería tener un solo assert.

En ocasiones se puede relajar.

Ej. tests de la misma funcionalidad.

SMALL

Page 76: TDD Course (Spanish)

F.I.R.S.T

Debe estar claro cual es el propósito de cada test.

Debe funcionar como documentación. Ejemplo de uso de la API que estamos testeando.

Ejemplo de uso del Object Under Test o Subject Under Test.

SIMPLICITY: debe ser sencillo, simple y fácil de leer.

Un test complejo es indicio de que el diseño está fallando.

Si un test se complica: plantearnos una refactorización.

Un test debería quedar claro incluso sin usar comentarios.

TRANSPARENT

Page 77: TDD Course (Spanish)

TESTS UNITARIOS: OTRAS CARACTERÍSTICAS

El Object Under Test NO debe tener código de test.

Aunque sí se recomiendan adaptaciones que faciliten su testing.

Pero la verificación (assert) siempre debe ser externa.

Los tests usados en TDD nunca deben cruzar fronteras. Ni comunicación entre maquinas ni entre procesos.

Dependencias externas convierten tests unitarios en tests de integración.

Si fallan las dependencias será complicado encontrar el fallo. Peor cuanto más extensa sea la cadena de dependencias.

Evitar el uso del depurador: aislando dependencias.

¿Qué convierte un test unitario en test de integración?

Habitualmente no se consideran librerías del sistema o de terceros.

Intentar el aislamiento entre módulos del sistema en desarrollo.

El uso de dependencias reales puede simplificar los tests.

El desarrollador debe valorar (dando preferencia a test aislados).

Page 78: TDD Course (Spanish)

RUNNING TDD

El test debe fallar: la funcionalidad aun no se ha codificado.

IMPORTANTE: evitar escribir falsos tests o código no probado. En la primera iteración el código ni siquiera compilará.

Pero en siguientes iteraciones se estará modificando código existente.

Es necesario asegurar que falla.

Este paso se tiende a olvidar: NO SALTÁRSELO NUNCA (*)

Cuando el test no falla.

Revisar la implementación del test y del código funcional.

Violación YAGNI:

Funcionalidad anticipada en una iteración anterior.

Se había codificado más de lo necesario.

Funcionalidad implementada sin su correspondiente test.

Peligro de acabar con código funcional no testeado.

2 - RUN THE TEST

* La importancia de hacer fallar los tests: ver notas.

Page 79: TDD Course (Spanish)

RUNNING TDD

CODIFICAR

Se codifica sólo lo necesario para satisfacer el test.

Programar el “ahora” no el “mañana” (YAGNI).

NO ANTICIPAR FUNCIONALIDAD Evitar el “por si acaso luego se necesita” (al final nadie lo usará).

Más productivo dejar para mañana lo que se necesita mañana.

La funcionalidad anticipada al final habrá que modificarla.

3 – MAKE A LITTLE CHANGE

“El esfuerzo de futuras modificaciones será menor que el esfuerzo de haber anticipado una funcionalidad, arquitectura o un diseño”

Page 80: TDD Course (Spanish)

RUNNING TDD

SIEMPRE DEBE EXISTIR UN TEST QUE FALLA Codificando la solución de un test pueden aparecer nuevas necesidades.

NO SE CODIFICAN AHORA

Se apuntan en el “Unit Test Backlog” para la siguiente iteración.

Por trivial que sea: no se codifica algo sin su correspondiente test.

Se corre el riesgo de dejar código sin cobertura de test.

FLEXIBILIDAD vs ANTICIPACIÓN Es fácil adaptarse a cambios de requisitos gracias a la cobertura de tests.

La refactorización hará emerger incrementalmente la arquitectura o el diseño flexible, desacoplado y modular que se persigue.

COLECTIVIDAD DEL CÓDIGO Deja de existir el “no lo voy a tocar por si acaso”.

Todos los desarrolladores pueden cambiar todo.

Los test unitarios avisarán si algo deja de funcionar.

3 – MAKE A LITTLE CHANGE

Page 81: TDD Course (Spanish)

CÓDIGO AUTO-EXPLICATIVO

MINIMIZACIÓN DE COMENTARIOS

Las prácticas Agile (XP o TDD) recomiendan la minimización de comentarios.

El código se evoluciona, pero los comentarios suelen acabar obsoletos.

Los comentarios no suelen tener mantenimiento: al final acaban desfasados.

Minimización, no eliminación. Los comentarios siguen siendo importantes y deben seguir existiendo.

Comentarios referidos a la semántica que no cambia.

Responsabilidades de módulos, clases o métodos.

Ej. JavaDocs, comentarios en las cabeceras de métodos, clases, etc.

NUNCA dejar en forma de comentario el código obsoleto. Si el código no sirve se elimina.

Si el código eliminado era necesario los tests avisarán.

La herramienta de SCM (Software Configuration Management) permite volver hacia atrás en cualquier momento.

Page 82: TDD Course (Spanish)

CÓDIGO AUTO-EXPLICATIVO

CÓDIGO SENCILLO, CLARO Y LIMPIO

Si hacen falta muchos comentarios, la solución se ha complicado.

Revisar la implementación o el diseño y refactorizar.

IDENTIFICADORES O SÍMBOLOS Identificadores significativos y auto-explicativos (mejor que comentarios)

Un nombre de clase, atributo, método, variable, etc. lo debe decir todo, no importa lo largo que sea.

Los IDEs actuales evitan tener que teclearlos (autocompletar).

La longitud no afecta al rendimiento del código compilado.

TESTS UNITARIOS COMO DOCUMENTACIÓN Son ejemplos de cómo se usa nuestro código.

Deben ayudar a entender el código mejor que cualquier comentario.

La documentación describe una API, pero los ejemplos la clarifican.

Complementan la documentación, no la sustituyen.

(*) Ejemplos de código autoexplicativo: Proyectos OpenSource, se entienden perfectamente casi sin comentarios.

Page 83: TDD Course (Spanish)

RUNNING TDD

Se continua ejecutando el test y codificando la funcionalidad.

Hasta que la funcionalidad de la iteración actual se completa.

Si se encuentra un bug no relacionado con la iteración actual: Se debe implementar un tests antes de corregirlo.

El test debe reproducir el bug encontrado y fallar.

La funcionalidad se codifica para corregir el test fallido.

Reparar los bugs sin codificar los tests: dejará código sin probar.

4 – RUN THE TEST

Page 84: TDD Course (Spanish)

RUNNING TDD

Modificar diseño e implementación sin alterar comportamiento.

Se plantea si es necesaria una refactorización:

Al finalizar y al empezar cada iteración.

REFACTORIZAR PARA:

Eliminar código repetido, arreglando el “copy & paste” realizado.

Extraer código reutilizable en librerías comunes.

Producir código legible, mantenible y extensible (funcionalidad y tests).

Mejorar arquitectura, diseño y codificación.

La refactorización es incremental: NO SE APLAZA.

Refactorizar el código funcional y el código de los tests.

Refactorización guiada mediante aplicación de los principios S.O.L.I.D.(*)

5 – REFACTOR

SIN REFACTORIZACIÓN NO EXISTE TEST DRIVEN DEVELOPMENT

Page 85: TDD Course (Spanish)

S.O.L.I.D.

SINGLE RESPONSIBILITY PRINCIPLE

OPEN/CLOSED PRINCIPLE

LISKOV SUBSTITUTION PRINCIPLE

INTERFACE SEGREGATION PRINCIPLE

DEPENDENCY INVERSION PRINCIPLE

Principios básicos de programación y diseño orientado a objetos cuya aplicaciónconjunta hace más probable la construcción de sistemas fáciles de extender y mantener.

(*) Introducidos por Robert C. Martin a principios del 2000.

Page 86: TDD Course (Spanish)

S.O.L.I.D

Un objeto debe tener una única responsabilidad, que debe estar enteramente encapsulada en una clase.

Toda la funcionalidad proporcionada por una clase debe estar estrechamente alineada con su responsabilidad.

Por extensión el mismo principio se aplica a los métodos.

Una clase o método deben resolver una sola problemática.

Una única responsabilidad = Una única razón para ser modificada.

En TDD refactorizamos para extraer responsabilidades.

Ejemplo: Un módulo que genera, formatea e imprime un informe.

Puede haber dos razones para modificarlo.

Cambiar el contenido o cambiar el formato.

Son dos responsabilidades, lo que implica dos clases.

SINGLE RESPONSIBILITY PRINCIPLE (SRP)

Page 87: TDD Course (Spanish)

S.O.L.I.D

Las entidades de software (clases, módulos, métodos, etc.) deben estar abiertas a extensiones pero cerradas a modificaciones.

Permitir cambios en su comportamiento sin necesidad de alterar su código fuente.

Varias formas de resolverlo. Herencia

Heredando se pueden sobreescribir métodos que cambian el comportamiento. Pero la clase está cerrada: se ha finalizado su responsabilidad. Se puede ampliar o modificar la funcionalidad heredando y sobreescribiendo.

Interfaces o clases abstractas Dependencias sobre entidades sin implementación. Se puede sustituir la implementación, cambiando el funcionamiento de una

colaboración sin afectar a los clientes de la interfaz.

Evitar construcciones del lenguaje que cierran a modificaciones. Ej. métodos o clases “final” en Java.

OPEN/CLOSED PRINCIPLE (OCP)

Page 88: TDD Course (Spanish)

S.O.L.I.D

Define la semántica de la relación “subtipo”.

Si q(x) es una propiedad demostrable sobre un objeto de tipo T. Entonces q(y) debe ser cierto para objetos de tipo S cuando es un subtipo de T.

Garantiza la semántica de interoperabilidad entre los tipos implicados en una jerarquía (semántica de la herencia).

Si un método acepta un tipo T, debe funcionar correctamente con objetos de cualquier tipo heredado de T.

El código que funciona sobre clases base debe seguir funcionando sobre clases heredadas.

Evita la violación de la semántica de las clases heredadas.Si una clase heredada modifica la semántica de la clase base, se empezarán a obtener fallos inesperados (normalmente a largo plazo) al usar los objetos en métodos creados para objetos de la clase base.

LISKOV SUBSTITUTION PRINCIPLE (LSP)

Page 89: TDD Course (Spanish)

S.O.L.I.D

Típico ejemplo de violación LSP.

Clase “Cuadrado” heredando de clase “Rectángulo”. Un cuadrado también tiene ancho y alto, aunque con el mismo valor.

El constructor de la clase cuadrado iguala ambos valores.

LISKOV SUBSTITUTION PRINCIPLE (LSP)

El método “ZoomToFit” trabaja sobre rectángulosy puede modificar las propiedades “length” y“witdh” de forma independiente.

Por herencia “ZoomToFit” acepta “cuadrados”.

El método desigualará los lados del “cuadrado”,rompiendo la semántica de la clase (o lapostcondición de igualdad de los lados).

Page 90: TDD Course (Spanish)

S.O.L.I.D

Evitar el diseño de interfaces extensas de propósito general.

Si una interfaz (o métodos públicos de una clase) ha crecido demasiado existirán muchos objetos que sólo usan una parte de la interfaz.

Será necesario dividir en varias interfaces más pequeñas y específicas.

Mejor pequeñas interfaces específicas que una sola de propósito general.

Los clientes de la interfaz (API) solo deben depender de lo que realmente utilizan. Ningún objeto debe ser forzado a depender de métodos que no utiliza.

Un solo jugador no puede estar molestando el resto del equipo.

Si una interfaz es extensa surgirán muchos clientes que solo necesitan una parte de la interfaz.

Indirectamente se estarán acoplando los objetos a la interfaz completa y tendrán más posibilidades de ser afectados por cambios en la interfaz.

INTERFACE SEGREGATION PRINCIPLE (ISP)

Page 91: TDD Course (Spanish)

S.O.L.I.D

Los objetos deben depender de interfaces en lugar de implementaciones.

Los objetos no crean o buscan las instancias de sus dependencias.

Los objetos permiten que las dependencias se configuren de forma externa.

DEPENDENCY INVERSION PRINCIPLE (DIP)

EJEMPLOGlobalAddressBook está fuertemente acoplada ala clase RadomIdGenerator.

Depende de una implementación específica ydebe crear o buscar la instancia utilizada.

APLICANDODIP

EJEMPLOCommandLineUI será encargado de crear lasinstancias y configurar las dependencias, que sóloestán basadas en interfaces.

Page 92: TDD Course (Spanish)

S.O.L.I.D

Principio para el desacoplamiento de dependencias.

Las relaciones de dependencia establecidas desde los niveles más altos a los más bajos de invierten(*). High-level modules should not depend on low-level modules. Both should

depend on abstractions.

Abstractions should not depend on details. Details should depend on abstractions.

Inversion of Control (IoC): Normalmente Direct Injection (DI).

IMPORTANTE: Para usar IoC no es necesario ningún framework.

Es un patrón de diseño, no hace falta Spring, JDK7, Plexus, etc.

La colaboración se basa en interfaces, y la implementación de las interfaces se entrega de forma externa.

DEPENDENCY INVERSION PRINCIPLE (DIP)

* Definición formal de DIP: la abstracción utilizada suele ser una Interfaz.Una buena explicación en: http://www.oodesign.com/dependency-inversion-principle.html

IoC: Hollywood Principle“Don’t call us, we’ll call you”

Page 93: TDD Course (Spanish)

S.O.L.I.D

OBJETIVO: Dividir responsabilidades usando acoplamiento débil.

SRP: Responsabilidades que se pueden extraer en forma de nuevas clases.

DIP: Las dependencias se gestionan aplicando el principio de inversión.

REFACTORIZANDO1. Localizar una responsabilidad que se puede extraer como una nueva clase.

2. Crear una interfaz para la nueva clase (sólo usará otras interfaces).

3. Las clases sólo dependerán de la interfaz (depender de especificación y no de implementación).

4. Los objetos no crean o buscan sus dependencias, no es su responsabilidad.

5. Habilitar la configuración externa de dependencias (Direct Injection,constructores, setters, getters, etc.).

6. Los clientes, contenedores o marcos de trabajo crean las instancias y configuran las dependencias.

DEPENDENCY INVERSION PRINCIPLE

Page 94: TDD Course (Spanish)

S.O.L.I.D

Permite crear un diseño altamente desacoplado. Cambiar la implementación de las dependencias sin modificar o recompilar

el código fuente, incluso por configuración en la plataforma de despliegue.

PROPORCIONA UN DISEÑO: Modular: Simplifica mantenimientos. El código se modifica en clases simples

y enfocadas en una sola responsabilidad.

Flexible: Modificar una dependencia o cambiar la implementación utilizada en niveles superiores no afecta ni al código fuente ni al compilado.

Configurable: Permite configurar las dependencias de forma externa, incluso en la plataforma de producción, sin recompilar el código.

Acoplamiento Débil: de módulos, unidades o clases.

EFECTO LATERAL: Facilita el aislamiento de los Unit Tests. Test aislados mediante la inyección de Mocks en el Object Under Test.

Podemos aislar el test unitario de sus dependencias reales o dirigir su ejecución (como si estuviéramos depurando con datos de prueba).

DEPENDENCY INVERSION PRINCIPLE

Page 95: TDD Course (Spanish)

S.O.L.I.D

CommandLineUI crea o busca las instancias concretas de la implementación de cada interfaz.Puede configurar la colaboración en tiempo de despliegue, seleccionando y configurando lasdependencias. Se pueden combinar diferentes implementaciones de GlobalAddressBook paraofrecer por ejemplo diferentes niveles de caché.

La clase CommandLineUI puede ser un contenedor genérico capaz de leer desde un fichero laconfiguración de dependencias e implementaciones para un despliegue concreto.

DEPENDENCY INVERSION PRINCIPLE (DIP)

Page 96: TDD Course (Spanish)

DISEÑO Y ARQUITECTURA

Principalmente durante la refactorización de cada iteración.

ANTICIPARSE A LA REFACTORIZACIÓN. La refactorización no implica hacer las cosas mal para luego corregirlas.

Durante la codificación de la funcionalidad (después del test) podemos directamente implementar buenos diseños, si los hemos identificado. Si se identifican responsabilidades se implementan directamente separadas. Las colaboraciones se implementan directamente aplicando DIP. Se evita el copy & paste con métodos privados o clases reutilizables. …

Los ejercicios del curso muestras un avance muy granular, para ejercitar los principios de la refactorización.

Cuanto más rápido se trabaje y con mejor calidad mejor.

Sin olvidar que no hay que anticipar semántica y funcionalidad.

Sin olvidar que no se codifica ni una línea de código sin su test.

¿CUANDO ESTAMOS DISEÑANDO CON TDD?

Page 97: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

UNIT TESTING FRAMEWORKS

Page 98: TDD Course (Spanish)

FASES DE UN TEST UNITARIO

SET UP

Preparar los Test Fixtures (REPEATABLE).

Instanciar el Object Under Test.

Preparar Test Objects (datos de ejemplo que se usan en los tests).

EXERCISE Interactuar con el Object Under Test (ejecutar el código a testear).

VERIFY Determinar que ha sido obtenido el resultado esperado.

TEAR DOWN Limpiar (INDEPENDENT) o desmontar los Text Fixtures.

FIXTURE: Estado predeterminado que fija la base de los test que se ejecutarán. Crear un conjunto de datos de prueba determinado (ej. base de datos en tests de integración). Preparar y configurar el Object Under Test. Preparar y configurar varios Test Objects. Preparar y configurar Mocks, Stubs, Fakes, etc. …

* Fixture o Test Context

Page 99: TDD Course (Spanish)

FASES EN LIBRERÍAS xUNIT

SET UP: setUp, Before, etc.

VERIFY: assertTrue, assertEquals, expectedException, etc.

TEAR DOWN: tearDown, After, etc.

CLASS SET UP & CLASS TEAR DOWN (afterClass, beforeClass)

PELIGRO: Violación del principio INDEPENDENT (code smell).

Prepara un Fixture que se reutilizará en todos los tests.

Tener mucho cuidado, mejor evitarlo (dependencias entre tests).

Se suele encontrar en tests de integración lentos.

EJEMPLO: Tests de Integración para Data Access Objects.

Class Set Up / Class Tear Down:Crea y destruye las tablas de la base de datos de pruebas (preferible en memoria). Los tests serían lentos si se hiciera antes y después de cada test.

Set Up / Tear Down: begin/rollback transaction (INDEPENDENT).El rollback permite comenzar siempre con un estado determinado, con la base de datos vacía, con los datos del Fixture común o de cada test.

Page 100: TDD Course (Spanish)

CICLO DE VIDA DE TESTS xUNITEstá diseñado para cumplir las propiedades F.I.R.S.T. Suele ser el mismo en todas las tecnologías o frameworks xUnit (JUnit, CppUnit, SUnit, PyUnit, JsUnit, etc.).

* http://en.wikipedia.org/wiki/XUnit#xUnit_Frameworks (arquitectura librerías xUnit)* http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks (lista completa de librerías xUnit)

EJEMPLO: Clase TestAddressBook (contiene 3 tests, un método cada test)

// Ejecución (simplificada) que realizará JUnit

// Crea todas las instancias, una para cada test, con sus propios atributos

// independientes(INDEPENDENT)

test1 = new TestAddressBook();

test2 = new TestAddressBook();

test3 = new TestAddressBook();

TestAddressBook.setUp() // Before Class

test1.setUp()

test1.testSomething() // Ejecución del test 1 sobre la instancia 1

test1.tearDown()

test2.setUp() // Before Test (INDEPENDENT)

test2.testAllThatStuff() // Ejecución del test 2 sobre la instancia 2

test2.tearDown() // After Test (REPEATABLE)

test3.setUp()

test3.testAnythingElse() // Ejecución del test 3 sobre la instancia 3

test3.tearDown()

TestAddressBook.tearDown() // After Class

Page 101: TDD Course (Spanish)

UNIT TEST CODE COVERAGE

Existe una teoría extensa de cobertura de tests (*)

Líneas de código funcional ejecutado.

Evaluación de expresiones en puntos condicionantes (branch coverage).

Herramienta para el seguimiento (SCRUM masters). Herramientas para informes de cobertura: Cobertura, Quilt, Clover, etc.

Establecer los niveles mínimos de cobertura exigidos.

Decidir el código que se cubre con test de alto nivel en lugar de unitarios (QA).

Decidir código al que no se le exige unit testing.

No es necesario exigir 100% de cobertura en los tests. Ej. propiedades respaldadas por atributo (generación automática, lenguajes con

soporte directo de properties, etc.)

Descubrimiento de código funcional innecesario, el test no lo ejecuta debido a que el código sobra (a veces sucede en condicionantes).

En ocasiones mucho código repetitivo y simple no necesita tests.

Programando con TDD se consigue amplia cobertura de forma natural.

* http://en.wikipedia.org/wiki/Code_coverage: Introducción y referencias sobre teoría de cobertura.de tests.

Page 102: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

DUMMY / FAKE / STUB / MOCK / SPY

Page 103: TDD Course (Spanish)

Dependency is the key problem in softwaredevelopment at all scales…. Eliminating duplication inprograms eliminates dependency.

— Kent Beck, Test-Driven Development: By Example

DUMMY / FAKE / STUB / MOCK / SPY

Page 104: TDD Course (Spanish)

DUMMY / FAKE / STUB / MOCK / SPY

DUMMY

Se entrega como argumento pero nunca se utiliza.

Sirve para cubrir requerimientos de parámetros.

FAKE

Exhibe una implementación completa pero simulada de un objeto.

Ej. HttpServletRequest que permite configurar parámetros de entrada, un DAO usando datos en memoria, etc.

STUB

Respuestas prefijadas con argumentos de entrada específicos.

Carece de la implementación “real” que tiene un FAKE, tan sólo devuelve respuestas programadas para llamadas concretas.

Permite dirigir el comportamiento del Object Under Test para forzar la ejecución del código a testear.

Ej. searchContact(“Pedro”): Contact / searchContact(“Edu”): null

Page 105: TDD Course (Spanish)

DUMMY / FAKE / STUB / MOCK / SPYMOCK

Evolución de un STUB que permite realizar verificación por interacción.

Definir expectativas en las llamadas a sus métodos.

Prueba si el Object Under Test utiliza las dependencias como se espera.

PELIGRO: No conviene abusar de la verificación por interacción.

Ej. verificar que únicamente se usa un método de la clase, que se llama N veces, que no se llama nunca, etc.

SPY

Partial Mock.

Utiliza una implementación real modificando alguno de sus métodos. Aplicando el principio Open/Closed (abierto a extensiones, cerrado a

modificaciones) se puede heredar y sobrescribir los métodos simulados.

PELIGRO: Mejor evitarlo, síntoma de code smell.

Útil para tests unitarios dentro de Heavyweight Frameworks. Frameworks rígidos no preparados para unit testing. Suele ser necesario para modificar comportamientos heredados desde el

framework por el Object Under Test (Ej. Servlets). (*) Mock: Se utilizará esta nomenclatura para nombrar de forma genérica todos los tipos.

Page 106: TDD Course (Spanish)

DUMMY / FAKE / STUB / MOCK / SPY

AISLAR TEST UNITARIOS (*)

Para ajustar el test a las propiedades F.I.R.S.T.

Para evitar interferencias de las dependencias en el código testeado.

Una cadena extensa de dependencias dificulta la localización de los bugs. El test unitario debería validar exclusivamente el código del Object Under Test.

Evitar que un test unitario falle por errores en las dependencias. Fallos que deberían ser detectados en los tests unitarios de dichas dependencias.

Evitar el uso del depurador para localizar el origen de los fallos.

FORZAR EJECUCIÓN DE CÓDIGO Forzar la ejecución del código que se quiere ejercitar en el test.

Evitar la dependencia sobre código con alta aleatoriedad (REPEATABLE).

Dirigir el comportamiento del Object Under Test en la ejecución del test.

VERIFICAR COLABORACIONES Probar que el Object Under Test usa correctamente sus dependencias.

PELIGRO: La verificación por interacción se debe minimizar.

PROPÓSITO

* Aislamiento de Test Unitarios: ver notas

Page 107: TDD Course (Spanish)

TIPOS DE VALIDACIÓN

Verificar que se devuelve el valor esperado o que el Object Under Test termina en un estado determinado (estado de las propiedades) después de la ejecución del test.

No se hacen suposiciones de cómo el Object Under Test utiliza sus dependencias.

Suele producir test de caja negra (menos frágiles).

Puede proporcionar menos cobertura de código testeado al no adaptarse a detalles específicos de la implementación.

VALIDACIÓN POR ESTADO

Page 108: TDD Course (Spanish)

TIPOS DE VALIDACIÓN

Verificar que el Object Under Test utiliza correctamente sus dependencias.

Suele producir test de caja blanca (más frágiles).

Revelan detalles de la implementación.

Permiten capturar los parámetros de las llamadas a las dependencias.

Posibilitando una forma de validación por estado en entornos poco adaptados al unit testing (Heavyweight Frameworks).

Usando mocks suele ser más sencillo idear validaciones por interacción.

Aunque conviene evitarlo ya que hacen el test más difícil de entender (menos claridad) y más acoplado a la implementación.

Los tests de caja blanca si son válidos en TDD (dirige el desarrollo).

Si el test se rompe tras cambios en la implementación, sólo hay que arreglarlo.

En la mayor parte de los casos se puede convertir una validación por interacciónen una validación por estado, programando la respuesta adecuada del stub.

VALIDACIÓN POR INTERACCIÓN

Page 109: TDD Course (Spanish)

VALIDACIÓN POR INTERACCIÓN

VER EJERCICIOS Y EJEMPLOS(*)

El desarrollo de la capa de lógica de negocio mediante TDDrequiere test unitarios aislados de la capa de persistencia (DAOs).

Es necesario utilizar mocks/stubs de las dependencias (DAOs).

Es fácil caer en el error de programar los tests de la lógica de negocio como verificaciones rigurosas de toda interacción (o falta de interacción) con la capa de persistencia.

PELIGROS Y RECOMENDACIONES

EVITAR LA EXCESIVA VALIDACIÓN POR INTERACCIÓNEVITAR VERIFICACIONES DE INTERACCIÓN REDUNDANTES

* Ejercicios Mocking Avanzado: Los controladores de la web se comenzaron con test de interacción (lo más inmediato) y al final se acabaron convirtiendo en test de validación por estado (con menos código y más legibles).

* Ejercicios Persistencia: implementación del servicio GlobalAddressBook basado en el uso de DAOs.

Page 110: TDD Course (Spanish)

VALIDACIÓN POR INTERACCIÓN

Convertir validación por interacción en validación por estado.

La misión principal de un mock/stub es proporcionar datos de ejemplo para las dependencias del Object Under Test.

Misión del test unitario: Únicamente verificar que la lógica del Object Under Test es correcta.

No debe verificar la lógica de las dependencias: antipatrón.

No debe verificar como utiliza sus dependencias, validando toda interacción o falta de interacción.

No es importante verificar que el resultado del código bajo prueba se produce utilizando ciertas dependencias.

EVITAR LA EXCESIVA VERIFICACIÓN DE INTERACCIONES

Page 111: TDD Course (Spanish)

VALIDACIÓN POR INTERACCIÓN

Asking an object of data: El resultado del código bajo prueba se genera mediante datos devueltos por las dependencias. STUBBING:

Las dependencias devuelven datos que permiten la ejecución del código.

Assert: Correcto si devuelve el valor esperado.

Una verificación por interacción sería redundante. El verify sería una copia exacta de la programación del stub.

Si el test no falla el resultado habrá usado el stub: interacción implícita.

Telling an object to do something: El código bajo prueba no devuelve un resultado, su misión es invocar alguna dependencia. MOCKING:

Las dependencias no devuelven datos, sólo ejecutan acciones.

Verify: Correcto si termina invocando la dependencia con los datos adecuados.

Un Test = Un único Assert o un único Verify.

El verify será el equivalente al assert, que ahora no podemos usar.

El verify es tan sólo un medio para realizar la afirmación.

TIPOS DE INTERACCIONES

Ver: http://monkeyisland.pl/2008/04/26/asking-and-telling/

Page 112: TDD Course (Spanish)

DEPENDENCIAS VS SUSTITUTOS

¿Cuándo utilizar objetos falsos o dependencias?

Lo debe decidir el desarrollador en función de la complejidad.

Intentar cumplir las propiedades F.I.R.S.T.

Usar las dependencias reales puede requerir menos trabajo. Se convierten en test de integración, si la cadena se alarga serán más frágiles.

Pueden complicar la localización y corrección de los errores.

El objeto falso permite aislar y realizar verificaciones por interacción. Pueden requerir más esfuerzo, pero aíslan de fallos de las dependencias.

La verificación por interacción acopla el test a la implementación.

El test unitario no realiza pruebas de integración (lo que se persigue en TDD).

RECOMENDACIÓN Usar el objeto real si la cadena de dependencias no es muy profunda.

Si cumple FIRST aunque sea de integración: no modifica datos, rápido, etc.

Usar las dependencias si el uso de mocks supone mucho código de test.

Mocks: más fácil cuanta más experiencia, las librerías lo convierten en un juego.

Page 113: TDD Course (Spanish)

GENERACIÓN AUTOMÁTICA DE MOCKS

Las librerías de generación de mocks convierten la creación y uso de mocks en un juego.

Java: JMock, EasyMock, Mockito, etc. Mockito: Simplicidad y documentación de pocas páginas (en XP y TDD la

simplicidad siempre debe tener un peso importante).

Otros lenguajes: mockcpp, MockitoPP, OCMock, NMock, etc.

Facilidades:

Todas las librerías de mocks en cualquier lenguaje o tecnología sesuelen fundamentar sobre la misma teoría y paradigmas, se usanprácticamente igual.

* http://en.wikipedia.org/wiki/List_of_mock_object_frameworks (lista de mock objects frameworks)* http://www.xprogramming.com/software (lista librerías y herramientas para XP y TDD)

Page 114: TDD Course (Spanish)

GENERACIÓN AUTOMÁTICA DE MOCKS

Las librerías de generación de mocks y frameworks de unit testing suelen contener características muy avanzadas.

TDD y XP promueven la simplicidad: conveniente restringirse siempre a lo más básico (creación de tests simples y claros). No hay que convertirse en un experto de las librerías (con dos o tres cosas es suficiente).

Más del 90% del unit testing se resuelve con menos del 10% de las facilidades de los frameworks.

La propia documentación de las librerías avisa de características peligrosas. Facilidades que cubren cualquier posible necesidad (testing de código legacy).

Avisan que el uso de algunas facilidades (ej. spy) produce malos diseños (code smell).

Indicador de la necesidad de refactoring Si los tests se complican o se necesitan características complejas de las técnicas o librerías

de mocks, quizás se está avanzando hacia un mal diseño (del código funcional), indicador de que se necesita refactorizar.

SOLID: Separando responsabilidades, usando la inversión de dependencias, etc. se pueden obtener mejores diseños y más fáciles de probar.

PELIGROS Y RECOMENDACIONES

Page 115: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

TEST DRIVEN DEVELOPMENT APLICADO A ENTORNOS ESPECÍFICOS

Page 116: TDD Course (Spanish)

CONTENEDORES / COMPONENTES

HEAVYWEIGHT FRAMEWORKSLa mayoría de los frameworks “legacy” son rígidos, pesados y no están optimizados para el Unit Testing.

LIGHTWEIGHT FRAMEWORKSActualmente la comunidad de desarrolladores propone y busca entornos ágiles basados en conceptos como: Don’t Repeat Yourself (DRY). Convention Over Configuration (CoC).

Lightweight Frameworks over Heavyweight Frameworks.

Plain Objects (clases simples débilmente acopladas con el framework).

EJEMPLOS EN JAVA Frameworks MVC con acoplamiento débil para aplicaciones web: SpringMVC. Inversión of Control se está incluyendo de forma nativa en lenguajes y librerías de

sistema: JDK7 (Direct Injection nativo), Spring IoC, Plexus, etc.

EJB 2.1 se simplifica en EJB 3.0 (conversión de frameworks heavyweight en lightweight) EJB 3.0 adopta conceptos de frameworks ligeros como Spring Framework. Uso de Plain Old Java Objects (POJO)

Entornos que además de proporcionar arquitecturas y diseños independientes, flexibles, desacopladas y ágiles, proporcionan mayor ayuda al unit testing.

Page 117: TDD Course (Spanish)

DECIDIENDO: UNIT TESTING VS INTEGRATION TESTING

Cumplen las propiedades FIRST: se pueden usar en TDD. Los test se deben lanzar continuamente en el equipo de cada desarrollador para poder

avanzar en los desarrollos con escala reducida de incrementos que propone TDD.

La misión de un Test Unitario es validar el código bajo prueba de forma aislada. El aislamiento se consigue utilizando mocks (o sus variantes).

Se puede utilizar test de integración de pequeña escala. CUIDADO: no convertir el test en un test de las dependencias del Object Under Test.

El test unitario prueba únicamente el código del Object Under Test. Se asume que las dependencias funcionan correctamente, se codificaron usando TDD.

El aislamiento es clave para no convertir el Unit Testing en una carga adicional.

Probar que de forma aislada el código acepta los datos de entrada, ejecuta el código sin errores y devuelve los datos esperados.

UNIT TESTS *

* Unit Test: Small Scaled Tests, test unitarios aislados o test de integración de pequeña escala.

Las capas de presentación y persistencia siempre representan un problema para sudesarrollo usando TDD, que se reduce a decidir entre Unit Tests o Integration Tests.

Page 118: TDD Course (Spanish)

DECIDIENDO: UNIT TESTING VS INTEGRATION TESTING

No cumplen las propiedades FIRST: no se pueden usar en TDD. No se pueden lanzar continuamente avanzando en pequeños incrementos.

No dirigen los desarrollos desde la codificación de forma tan directa.

Se pueden automatizar por adelantado: Test First Development.

Se ejecutarán de forma más espaciada (más lentos). Cada x horas o minutos, en cada commit, etc.

Tareas configuradas en la herramienta de Integración Continua.

Suelen ser propiedad del grupo de calidad, testing o QA.

NECESARIOS: validan las colaboraciones y detectan los fallos que no se pueden detectar con test unitarios.

Test de Integración en TDD. Se pueden usar test de integración de pequeña escala para simplificar código.

El desarrollador puede mantener una batería paralela de test de integración.

INTEGRATION TESTS *

* Integration Test: O también test funcionales, no funcionales, de aceptación de sistema, de interfaz de usuario, etc.

Page 119: TDD Course (Spanish)

CAPA DE PRESENTACIÓN Y PERSISTENCIA

Evitar la excesiva redundancia en el código de los tests.

Muchos test unitarios se pueden reutilizar como test de integración con solo cambiar las dependencias en la plataforma de preproducción.

Valorar si es más productivo usar test de integración.

Los test unitarios podrían requerir un uso intensivo de mocks.

Los test de integración podrían ser una repetición de los test unitarios.

Programando con TDD se intenta aligerar código de las capas de presentación y persistencia.

¿Merece la pena crear test unitarios para capas tan ligeras?

¿Es más productivo si directamente programamos test de integración?

¿Existe un grupo de QA programando buenos test de sistema?

¿Podemos aprovecharlo para evitando la redundancia en capas complicadas?

No existe receta mágica, se debe valorar la situación específica.

RECOMENDACIONES

* Ver notas de la diapositiva.

Page 120: TDD Course (Spanish)

CAPA DE PRESENTACIÓN Y PERSISTENCIA

Minimizar la lógica de las capas difíciles de testear.

PERSISTENCIA (código de acceso a datos): Usar Data Access Objects.

Se extrae y se centraliza el código de acceso a base de datos (SRP).

PRESENTACIÓN: Usar arquitecturas MVC, delegando la “C” sobre la capa de negocio.

El controlador delega todo el trabajo sobre la capa de negocio.

El controlador solo contiene código repetitivo de validación de entrada, acceso a la capa de negocio, publicación del modelo y redirección a la vista adecuada.

Plantear cambio de test unitarios por integración (o sistema).

El código de estas capas será muy simple y repetitivo.

Será sencillo localizar fallos en estas capas aunque solo cuenten con test de integración o sistema.

RECOMENDACIONES

Page 121: TDD Course (Spanish)

CAPA DE PRESENTACIÓN

Minimizar el código existente en la capa de presentación. Nunca debe contener lógica de negocio.

La funcionalidad especificada mediante los test de aceptación (ATDD).

Solo debe contener código directamente relacionado con la Interfaz de Usuario.

Dividir responsabilidades: Arquitecturas MVC. VISTAS

Renderizan el modelo que han construido los controladores.

No suelen admitir Unit Testing: Muchas veces usan lenguajes declarativos.

MODELO Clases simples que solo contienen propiedades (o los objetos del dominio).

Unit Testing si contienen lógica específica: por ejemplo propiedades generadas en lugar de respaldadas por atributos.

CONTROLADOR Delegar toda la lógica sobre los objetos de la capa de negocio.

Tareas repetitivas: Procesar la entrada del usuario, exportar un modelo a las vistas, seleccionar la vista y entregarla al usuario.

El desarrollador debe decidir si crear test unitarios o depender de test de más alto nivel.

Muy repetitivo: seguro que se puede reutilizar código de test en todos los controladores

La lógica de presentación en conjunto quedará probada por test de integración, de sistema o de interfaz de usuario (si se dedican recursos de QA).

Page 122: TDD Course (Spanish)

CAPA DE PRESENTACIÓN

Extraer responsabilidades aplicando el principio SRP

Independizar o extraer la lógica compleja de los controladores. Extracción de datos entregados por el usuario, validación y conversión de los

datos, etc.

Responsabilidades con lógica específica de presentación pero que puede ser extraída y reutilizada. Ej. Validación y conversión de una fecha en forma de texto.

Lógica que debe ser desarrollada con TDD (con sus tests unitarios). Se puede testear fácilmente si se extrae de los controladores.

EjerciciosLa lógica de extracción, verificación y conversión de los datos introducidos en un formulario se ha extraído desde AddContactController en la nueva clase ContactCommandConverter que ahora tiene tests específicos de la lógica.

Page 123: TDD Course (Spanish)

CAPA DE PRESENTACIÓN

La programación de pruebas unitarias presenta dificultades cuando sedepende de un entorno de contenedor no preparado para el UnitTesting (Heavyweight Framework).

Dificultades para cumplir con las propiedades FIRST (uso exhaustivode mocks).

Es preferible contar con un framework MVC ligero (LightweightFramework) que permita aislar fácilmente los controladores, yproporcione utilidades especificas para el testing.

APLICACIONES WEB

Page 124: TDD Course (Spanish)

APLICACIONES WEB

Parámetros de entrada y salida: uso de fake/stub/mock/spy.

El contenedor es el encargado de crear los parámetros de entrada y salida.

Ej. En un servlet la entrada y salida es el request y response, y el código puede alterar el estado de objetos compartidos como el context y session.

Creación de fakes o librerías de terceros con fakes completos. Ej. El HttpServletRequest no proporciona un setParameter. Mocks de Sprint

Tests Utilities o HttpServlet Unit.

IN-CONTAINER UNIT TESTING

Ejecutar los test unitarios directamente en el contenedor de preproducción.

Evita el uso de mocks usando los objetos reales del contenedor.

Los tests unitarios son exactamente iguales, pero sin utilizar mocks.

Ej. Java: CACTUS.

Permite ejecutar Unit Tests de Serlvets, Filters, JSPs, EJBs, etc en cualquier contenedor J2EE.

UNIT TESTING

Page 125: TDD Course (Spanish)

APLICACIONES WEB

Herramientas que permiten la programación test de sistema o integración. Independientes de la tecnología utilizada en el desarrollo de la aplicación web. Lanzan peticiones HTTP y proporcionan diferentes herramientas de verificación.

EJEMPLOS HTTP Client Library: cualquier cliente HTTP permite la ejecución de pruebas de

integración sobre una aplicación web, una api rest, una api soap, etc. Ej. curl, httperf, Apache HttpClient, etc.

Programación y simulación manual del entorno del browser y la verificación de respuestas.

HtmlUnit: Los test se deben programar en Java (no la aplicación web). Emula navegadores específicos sobre la máquina virtual de Java.

Selenium: La programación de los test se puede realizar con: HTML, Java, C#, Perl, PHP, Python, y Ruby. Proporciona un IDE de generación automática de tests. Ejecuta los test sobre un navegador real en un sistema operativo determinado.

Ambos permiten lanzar las peticiones simulando eventos sobre el DHTML. Ofrecen facilidades de verificación del contenido de las páginas web a cualquier nivel de detalle, estructura de navegación, Test de Aceptación, etc.

INTEGRATION TESTING

“¿Qué se debería verificar en los test de integración?”“¿Es conveniente incluso la verificación de un CSS?”

Page 126: TDD Course (Spanish)

APLICACIONES DESKTOPLa interfaz de usuario de una aplicación de escritorio (o unaaplicación para móvil) se puede desarrollar usando TDD.

Si existe código ejecutable se puede programar un test unitario.

Las aplicaciones para móviles se desarrollan sobre un equipo, portanto se pueden ejecutar los test unitarios en el IDE de desarrollo.

UNIT TESTING

Se aplican las ideas comentadas para la capa de presentación. Utilización de arquitecturas MVC: centralización de la lógica del GUI. Delegación en la lógica de la capa de negocio. Extracción de la lógica compleja y específica en forma de responsabilidades.

INTEGRATION TESTING

Herramientas para la programación de test de sistema y de integración.

Permiten la manipulación de la Interfaz de Usuario desde el código.

Herramientas específicas, limitadas y complejas.

Ej. UIAutomation, NUnitForms, etc.

Page 127: TDD Course (Spanish)

CAPA DE PERSISTENCIA

Aplicar las ideas ya expuestas para la capa de persistencia.

Centralización de la lógica de acceso a datos en Data Accesss Objects (DAO).

Los sistemas de Object Relational Mapping (ORM) alivian el unit testing.

DECIDIR: Integration Testing vs Unit Testing.

EJEMPLO DE TÉCNICAS MÁS COMUNES Frameworks de testing de base de datos (Ej. DbUnit).

Bases de datos embebidas o en memoria (Standard SQL)

Base de datos de desarrollo o preproducción (rollback al finalizar cada test para inicializar los datos de prueba).

Desde un punto de vista purista, los test que ejercitan el código deacceso a base de datos no pueden ser considerados test unitarios, yaque dependen de una entidad externa, la base de datos.

¿Son test de Integración? ¿Test funcionales? ¿Test No Unitarios?

No hay receta mágica: la categoría dependerá del contexto.

Page 128: TDD Course (Spanish)

EXPLORATORY TESTING - SPIKE SOLUTIONS

Acceptance Test Driven Development (ATDD) propone actividades de Exploratory Testing al finalizar la fase de desarrollo.

Extreme programming propone la creación de Spike Solutions: pequeños testsque permiten la exploración de alternativas.

Reducción del riesgo: Desarrollo de pequeñas alternativas para la acotación de riesgos (test de rendimiento, de carga, etc.).

Diseño basado en el aprendizaje del sistema a producir mediante la exploración de alternativas a través del testing.

Aprendizaje de nuevas tecnologías mediante la experimentación. No recomendable la aplicación de nuevas tecnologías, frameworks o arquitecturas sin un

conocimiento básico de su funcionalidad y las repercusiones sobre el sistema.

Discusión de ideas: Explicar soluciones mediante el código y sus tests.

A style of software testing that emphasizes the personal freedom andresponsibility of the individual tester to continually optimize the quality ofhis/her work by treating test-related learning, test design, test execution,and test result interpretation as mutually supportive activities that run inparallel throughout the project.

— Cem Kaner (*)

* Cem Kaner: Profesor de Ingeniería del Software en el Florida Institute of Technology, Director del Florida Tech's Center for Software Testing Education & Research.

Page 129: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

ANTI-PATRONES Y MALAS PRÁCTICAS

Page 130: TDD Course (Spanish)

TDD ANTI-PATTERNSExtraído del blog: http://blog.james-carr.org/2006/11/03/tdd-anti-patterns/— James Carr.

•EL MENTIROSO. Todos los asserts se cumplen pero el test no está probando la funcionalidad que realmente se quería probar.

THE LIAR

•EXCESIVA CONFIGURACIÓN . Demasiado código en los Fixtures o configuración, que impide ver lo que se está probando o la finalidad del test.

EXCESSIVE SETUP

•EL GIGANTE. El test es correcto pero contiene demasiado código, probando muchos casos de uso. O una clase de test con una cantidad enorme de tests. Indica necesidad de aplicar SRP.

THE GIANT

•EL EMULADOR. Se abusa de los mocks, stubs o fakes. El sistema no acaba siendo testeado, se están validando los datos devueltos por los mocks. Demasiada verificación por interacción. El test es un reflejo del código funcional, que tan solo prueba cómo se usan las dependencias.

THE MOCKERY

Page 131: TDD Course (Spanish)

TDD ANTI-PATTERNS

• EL INSPECTOR. Test que viola la encapsulación (partes privadas) o desvela demasiados detalles de implementación para conseguir 100% de cobertura. Cualquier refactorización posterior romperá el test.

THE INSPECTOR

• SOBRAS ABUNDANTES. Tests que violan la propiedad de independencia. Los datos de un test se mantienen y no se limpian, aprovechándose o interfiriendo en otros tests.

GENEROUS LEFTOVERS

• EL HÉROE LOCAL. Los tests solo funcionan en una plataforma específica o con una configuración específica. No sirven para TDD, los tests se deben ejecutar en el equipo de cualquier desarrollador.

THE LOCAL HERO

• EL QUISQUILLOSO. El test valida la salida completa o demasiados detalles no significativos. Cada pequeño cambio requiere el mantenimiento del test. (Ej. Comparar el title o el css de las páginas html de una aplicación web).

THE NITPICKER

Page 132: TDD Course (Spanish)

TDD ANTI-PATTERNS

•CAZADOR SECRETO. Parece que no realiza verificaciones por ausencia de asserts, pero en realidad verifica que no se lanza alguna excepción. Conviene aclarar la finalidad capturando la excepción y finalizar con un fail.

THE SECRET CATCHER

•EL DESERTOR. Test que prueba muchos efectos colaterales, pero no termina de probar la autentica funcionalidad el Object Under Test. Ej. Verificar que no se alteran datos, o no se ejecutan ciertos métodos de las dependencias, etc.

THE DODGER

•EL ALBOROTADOR. Llena la consola de demasiados datos de diagnostico, trazas, mensajes, etc. incluso cuando se pasan los tests. Algunas veces se crean estas trazas durante la codificación de los test, y al final se dejan aunque no sean necesarios (enturbiando los resultados).

THE LOUDMOUTH

•CAZADOR GLOTÓN. Captura e ignora las excepciones (aunque escriba trazas), dejando pasar los tests. Problemática muy habitual en aplicaciones Java (incluso en código funcional).

THE GREEDY CATCHER

Page 133: TDD Course (Spanish)

TDD ANTI-PATTERNS

• EL SECUENCIADOR. Fija el orden de los resultados. Los asserts esperan que los resultados se reciban siempre en el mismo orden (métodos que devuelven listas).

THE SEQUENCER

• DEPENDENCIA OCULTA. Test que presupone la existencia de ciertos datos de test en la plataforma de ejecución. Otros desarrolladores deben descubrir que datos se supone que deberían existir.

HIDDEN DEPENDENCY

• EL ENUMERADOR. Los nombres de los métodos de test son sólo una enumeración como test1, test2, test3, en lugar de utilizar nombres significativos que indiquen la intención de cada uno de los tests.

THE ENUMERATOR

• EL EXTRAÑO. Test que está realizando pruebas sobre un objeto que no pertenece al Object Under Test de la clase de test. Una clase de test se debería encargar de los test de una sola clase del código funcional. También El Pariente Lejano (Distant Relative).

THE STRANGER

Page 134: TDD Course (Spanish)

TDD ANTI-PATTERNS

•EVANGELISTA DEL SISTEMA OPERATIVO. Los test que dependen de caracteristicas del sistema operativo. Ej. Suposiciones de los caracteres de nueva línea, comandos de la shell, etc.

THE OPERATING SYSTEM EVANGELIST

•A PESAR DE TODO FUNCIONA. Se escribe el código funcional antes de hacer fallar al test aunque este se escribiera antes, o se escriben test sobre código que ya existe. Un efecto lateral es que el test puede pasar aunque el código tenga fallos.

SUCCESS AGAINST ALL ODDS

•DOS POR UNO. En lugar de escribir un nuevo test para probar una nueva funcionalidad, se añade un nuevo assert en un test ya existente.

THE FREE RIDE

•EL ÚNICO. Combinación de varios patrones (Free ride and Giant). Un solo método de test que prueba todos los casos de uso del objeto en secuencia. Contiene múltiples fixtures y asserts.

THE ONE

Page 135: TDD Course (Spanish)

TDD ANTI-PATTERNS

• EL MIRÓN. Debido a recursos compartidos un test puede ver los resultados de otro test y puede hacer que el test falle incluso cuando el sistema testeado es válido. Suele producirse con el uso de variables de clase (miembros estáticos). También conocido como The Uninvited Guests.

THE PEEPING TOM

• EL TORTUGA. Un test increíblemente lento. No apto para el desarrollo con TDD, si no para tests ejecutados en la herramienta de integración continua.

THE SLOW POKE

Page 136: TDD Course (Spanish)

MALAS PRACTICAS

IGNORAR LAS PROPIEDADES F.I.R.S.T.

Propiedades ideadas para la aplicación de TDD como una metodología de desarrollo, iterativa, incremental, a pequeña escala y dirigida por unit tests.

No están ideadas para su utilización en metodologías de testing.

NO DEJAR CLARO CUAL ES EL OBJECT UNDER TEST Test en los que se confunde el Object Under Test entre el resto de Test

Objects, mocks, etc.

El Object Under Test debería ser lo más sencillo de identificar.

NO REFACTORIZAR en cada iteración No se estaría usando la metodología TDD.

La refactorización no se aplaza (los momentos de descanso no existen).

TEST DIFÍCILES DE ENTENDER

Deben funcionar como documentación o ejemplos de nuestra API.

Nombres de tests y código auto-explicativo (fijar estándares).

Page 137: TDD Course (Spanish)

MALAS PRACTICAS

VARIOS CASOS DE PRUEBA EN UN SOLO TEST

Se debe separar en diferentes métodos de test, cada test solo un assert.

Excepto cuando son asserts que pertenecen a una misma funcionalidad.

MEZCLAR TEST DE INTEGRACIÓN CON TEST UNITARIOS Se deben mantener en carpetas o proyectos independientes aunque ambos

se puedan escribir usando librerías xUnit.

CONVERTIR TEST UNITARIOS EN TEST DE DEPENDENCIAS

El test unitario debe probar única y exclusivamente el Object Under Test.

Aunque se usen dependencias reales, se asume que tienen sus tests.

ABUSAR DE LA VERIFICACIÓN POR INTERACCIÓN Problemática vista en el tema de mocks y antipatrones.

Si los tests tan solo contienen verify sobre lo mocks, revisar los tests.

Page 138: TDD Course (Spanish)

ACCEPTANCE TEST DRIVEN DEVELOPMENT

ACCEPTANCE TEST DRIVEN DEVELOPMENT EXPLAINED

Page 139: TDD Course (Spanish)

ACCEPTANCE TEST DRIVEN DEVELOPMENT

ATDD es una metodología relativamente reciente comparada con el resto de metodologías Agile, aun no hay mucha literatura disponible.

http://www.dosideas.com/wiki/Acceptance_Test_Driven_Development

Pequeña introducción y enlaces a herramientas de automatización.

http://www.methodsandtools.com/archive/archive.php?id=72

Acceptance TDD Explained (Artículo de diez páginas)

http://www.methodsandtools.com/archive/archive.php?id=23

Using Customer Tests to Drive Development

Practical TDD and Acceptance TDD for Java Developers, 2007, LasseKoskela, Manning Publications

http://www.manning.com/koskela/

Acceptance Test Engineering Guide, 2009, Grigori Melnik, Gerard Meszaros, Jon Bach, Microsoft

REFERENCIAS

Page 140: TDD Course (Spanish)

ACCEPTANCE TEST DRIVEN DEVELOPMENT

“Se acerca más a una metodología de especificación de requisitos que una metodología de testing”

NOMENCLATURA

Acceptance Test Driven Development (ATDD)

Story Test Driven Development (STDD)

Customer Test Driven Development (CTDD)

Page 141: TDD Course (Spanish)

ACCEPTANCE TEST DRIVEN DEVELOPMENT

Permitir al cliente obtener un feedback del avance del desarrollo mediante las pruebas de aceptación.

Pruebas de cliente: el cliente puede ser reacio a validar unos tests que comprometen la aceptación del producto.

Obtener una especificación de requisitos mas concreta y menos ambigua mediante el uso de ejemplos.

Los Users Stories se describen mediante ejemplos concretos de uso.

Los User Stories ya no se describen mediante la redacción de descripciones.

Ayudar al cliente a entender lo que realmente quiere

Haciéndolo consciente de la casuística de todos los User Stories

Ayudar a los desarrolladores a entender lo que quiere el cliente.

Concretando el comportamiento de cada User Story y evitando la libre interpretación de la casuística no contemplada en la especificación.

ESPECIFICACIÓN DE REQUISITOS EJECUTABLE

OBJETIVOS

Page 142: TDD Course (Spanish)

ACCEPTANCE TESTS VS UNIT TESTS

ACCEPTANCE TESTS

• Escritos por los “clientes”.

• Qué hace el sistema.

• Tests de Features (Backlog).

• Vocabulario del negocio.

• Sin detalles implementación.

UNIT TESTS

• Escritos por desarrolladores.

• Cómo se hace el sistema.

• Tests del código.

• Vocabulario de la solución.

• Detalles de implementación.

Page 143: TDD Course (Spanish)

ACCEPTANCE TESTS

CRITERIO DE FINALIZACIÓN Proporcionado por el “cliente” a los desarrolladores.

Especificando cada User Story mediante ejemplos.

FOMENTA LA COMUNICACIÓN Fuerza a clientes, testers y desarrolladores a trabajar juntos.

RAPID FEEDBACK Herramienta para el Project Management.

Datos reales para medir el avance del desarrollo.

Total de test de aceptación, total fallidos y total cumplidos.

PROPORCIONAN

Page 144: TDD Course (Spanish)

CRITERIOS DE ACEPTACIÓN

Son el conjunto de condiciones que debe cumplir la historia (UserStory) para ser aceptada como completada.

Normalmente proporcionados por el cliente o product owner.

“No son sustitutos de la conversación”“Es uno de los resultados de la conversación”

“Los Criterios de Aceptación NO son los Tests Aceptación”

Los criterios de aceptación se componen de:

Actor

Verbo (que describe un comportamiento del actor sobre el sistema)

Resultado observable

Page 145: TDD Course (Spanish)

ACCEPTANCE TESTS

=CRITERIOS DE ACEPTACIÓN

+EJEMPLOS

(DATOS + ESCENARIOS)

ACCEPTANCE TESTS

Page 146: TDD Course (Spanish)

AUTOMATED ACCEPTANCE TESTS

CRITERIO PARA EL FINALIZADO Un User Story debe tener al menos un test de aceptación.

Un User Story está terminado cuando pasa todos sus tests de aceptación.

AUTOMATIZACIÓN Especificación de alto nivel pero en un lenguaje conciso.

Detalles no ambiguos.

EJEMPLOS REALISTAS

Descripción de la interacción de los actores con el sistema.

ESPECIFICACIÓN DE REQUISITOS EJECUTABLE Paradigma de testing basado en Test de Aceptación.

Especificación de Requisitos: la calidad es lo primero.

Una especificación ejecutable elimina la ambigüedad de los requisitos.

Page 147: TDD Course (Spanish)

AUTOMATED ACCEPTANCE TESTS

ESPECIFICACIÓN EJECUTABLE

=CRITERIO PARA EL FINALIZADO

+TESTS DE ACEPTACIÓN AUTOMATIZADOS

LOS TESTS DE ACEPTACIÓN SE DEBEN AUTOMATIZAR

Page 148: TDD Course (Spanish)

ACCEPTANCE TESTS

Colaboración con el cliente: Business Analyst Quality Assurance Product Owner Developer

Los tests requieren una componente técnica. El “cliente” necesita ayuda para escribir los tests. Los desarrolladores y QA conocen la parte técnica. Pair Test Authoring.

Las reglas del negocio suelen ser confusas. Los desarrolladores necesitan ayuda para entender los tests. El cliente conoce las reglas del negocio. Pair Test Implementation.

COMUNICACIÓN En definitiva se trata de comunicación entre todos los implicados en el sistema. Al menos el Cliente o Product Owner y el Analista del Negocio. Se ayuda al cliente a pensar y localizar ejemplos.

QUIEN DEBE ESCRIBIRLOS

Page 149: TDD Course (Spanish)

ACCEPTANCE TESTS

Construir un entorno que permita el testing

Los test de aceptación deben estar automatizados.

Ser especifico y concreto

Evitar escenarios genéricos.

Ej. “añadir contactos al sistema”, “comprobar que existen en la agenda”, etc.

Usar ejemplos concretos.

Ej. “añadir contacto “Pedro”, “comprobar que existe el contacto “Pedro”, etc.

No permitir la ambigüedad.

Evitar detalles de implementación Se debe utilizar el vocabulario del negocio.

Nunca utilizar el vocabulario de la implementación.

Añadir el registro (“Pedro”, “6090909”) a la tabla “contacts”.

Validar que se devuelve el ID del contacto.

Abrir el navegador en la URL http://localhost/contacts.

ESCRIBIENDO LOS TEST DE ACEPTACIÓN

Page 150: TDD Course (Spanish)

PROPIEDADES DE ACCEPTANCE TESTS

SPECIFIC Explicitly defined and definite

MEASURABLE Possible to observe and quantify

ACHIEVABLE Capable of existing or taking place

RELEVANT Having a connection with the story

TIME BOUND When will the outcome be observed

LAS RENOMBRADAS PROPIEDADES SMART

Page 151: TDD Course (Spanish)

ACCEPTANCE TESTS

Son test de sistema que pueden ser funcionales o no funcionales. Muestran lo acabado que está el sistema.

Se deben ejercitar en la plataforma de preproducción.

Mostrando el funcionamiento end-to-end.

Los Tests de Interfaz de Usuario muchas veces no se incluyen como AT. Los test de aceptación especifican qué hace el sistema, no como se usa.

Desarrollo dirigido por test de UI: arquitectura demasiado acoplada a la UI.

La funcionalidad del sistema debe ser independiente de la UI proporcionada.

Posibilidad de ofrecer múltiples UI o cambiarla (nuevas veriones) sin modificar la lógica ni romper los tests de aceptación.

Si se fija como un requisito de aceptación: Incluir test de UI. En ciertas plataformas son complejos o inviables de automatizar.

Test frágiles que requieren mantenimiento, o grandes esfuerzos para hacerlos independientes del look & feel, del idioma, etc.

¿Una batería de tests para cada versión de la Interfaz de Usuario?

OTRAS CARACTERÍSTICAS

Page 152: TDD Course (Spanish)

ACCEPTANCE TESTS

Permitir a los clientes añadir nuevos tests sin romper el build.

Mantener los test de aceptación junto con el código en el sistema de control de versiones.

Independencia: unos test no deberían depender de otros

Dejar el sistema en el mismo estado que estaba antes de la ejecución de los tests.

Utilizar herramientas de Integración Continua.

Evitar dependencias de sistemas externos (que no son objeto de los test de aceptación o el sistema desarrollado).

Escribir los tests tan próximos al entorno real como sea posible (entorno de preproducción)

Evitar test demasiado extensos o multipropósito.

BUENAS PRACTICAS

Page 153: TDD Course (Spanish)

ACCEPTANCE TESTS

Desarrolladores escribiendo tests de aceptación ellos mismos y para ellos mismos.

Escribir tests de aceptación como tests unitarios

Los test unitarios son específicos de la implementación.

Los test de aceptación son específicos del negocio.

Escribir test de aceptación que son dependientes de detalles de implementación o de las estructuras de datos.

MALAS PRACTICAS

Page 154: TDD Course (Spanish)

FLUJO DE TRABAJO COMPLETO ATDD + TDD

Propuesta habitual de flujo de trabajo, que puede ser adaptada: A las características particulares del desarrollo. Test de UI como test de aceptación (intentar evitarlo). Decisiones de automatizar por adelantado de ciertos grupos de tests. Trabajos de testing visual o automático de un grupo de QA.

ATDD DIRIGE LOS SPRINTS Y TDD LOS DESARROLLOS

Los test de aceptación se obtienen a partir de los criterios de aceptación

de las historias.

Se desarrolla usando TDDen incrementos iterativos de escala muy reducida. Cumplidos los test de

aceptación, se puede lanzar una fase de

Exploratory Testing.

Cumplidos los criterios de aceptación, se pueden

automatizar tests para las interfaces de usuario.

Finalmente se lanzan test no funcionales (carga,

stress, rendimiento, etc.).

Page 155: TDD Course (Spanish)

CICLO DE TRABAJO EN ATDDTRABAJOS EN EL COMIENZO Y FIN DE LOS SPRINTS

Modelo del ciclo ATDD desarrollado por James Shore, con cambios sugeridos por Grigori Melnick, Brian Marick, and Elisabeth Hendrickson.

Page 156: TDD Course (Spanish)

CICLO DE TRABAJO EN ATDD

Desarrollo del mecanismo de login o autenticación de un sistema.

Crear una cuenta con un nombre y una password.

Entrar en la cuenta con el nombre y la password válida.

Se prioriza la siguiente User Story del Product Backlog.Se requiere que los usuario usen una password segura (cadenas de al menos 6 caracteres con al menos una letra, un número y un símbolo).

DESCRIPCIÓN A TRAVÉS DE UN EJEMPLO

Page 157: TDD Course (Spanish)

CICLO ATDD

Sprint Planning: Discusión de los User Stories priorizados, lanzando al cliente preguntas que intentan fijar los criterios de aceptación.

¿Que pasa si el usuario introduce una password insegura?

¿Me puedes dar un ejemplo de password que se considera insegura?

¿Cuales serían ejemplos de “símbolos”? ¿Como se tratan los espacios en blanco?

¿Como se podrá saber que esta característica “funciona”?

Haciendo las preguntas correctas hacemos que el cliente piense cuidadosamente en sus expectativas para la funcionalidad.

Algunas expectativas pueden acabar convirtiéndose en nuevas User Stories (se pueden tratar ahora o en el siguiente sprint).

Entendido lo que quiere el cliente se pueden bosquejar ejemplos concretos de los criterios usando un lenguaje natural.

Password que devuelven ok: “p@ssw0rd”, “@@@000dd”, “p@ss w0rd”, “p@sw0d”.

Password que devuelven error: “password”, “p@ss3”, “passw0rd”, “p@ssword”, “@@@000”

1 - DISCUSIÓN

Page 158: TDD Course (Spanish)

CICLO ATDD

Una vez obtenido el borrador de los criterios de aceptación, se capturan como tests de aceptación usando un formato adaptado al framework de automatización.

Deben quedar expresados lo más claro y entendible posible. Sin preocuparse (todavía) en cómo automatizarlos (conexión con el código).

Enfocarse en la esencia del test ignorando detalles de implementación.

Test Case Action Argument

Verificar passwords válidas e inválidas

La password debe ser válida p@ssw0rd

La password debe ser válida @@@000dd

La password debe ser válida p@ss w0rd

La password debe ser inválida password

La password debe ser inválida p@ss3

La password debe ser inválida Passw0rd

2 - DESTILAR

Page 159: TDD Course (Spanish)

CICLO ATDD

Se puede utilizar la forma canónica propuesta por Mike Cohn: As a <type of user>, I want <some goal> so that <some reason>

Ej. “As a user of the word processor, I want to select a word and specify that it be italics, so that I can add emphasis to my writing”.

Algunas herramientas de test de aceptación se basan en este formato.

Otras fuentes indican que no es necesario: resulta repetitivo y monótono.

Lo ideal es utilizar el mismo formato que utilice nuestra herramienta de automatización de test de aceptación.

En cualquier caso se debería considerar las siguientes indicaciones: Who will use this feature?

What do they want the system to do?

What larger goal of the user does this support?

What will tell me that this story is done?

2 - DESTILAR

Page 160: TDD Course (Spanish)

CICLO ATDD

UTILIZANDO TEST DRIVEN DEVELOPMENT

Se comienzan los trabajos del Sprint planificado.

Se pueden codificar los test de aceptación en la herramienta utilizada aunque aun no se puedan conectar con el código.

Se implementa la funcionalidad especificada con los Tests de Aceptación usando el bucle TDD.

Iteraciones incrementales y continuas de pequeña escala, dirigidas por test unitarios.

3 - DESARROLLO

Page 161: TDD Course (Spanish)

CICLO ATDD

Demostración de la funcionalidad al finalizar el Sprint.

Se puede realizar una fase previa de Exploratory Testing. Tests de exploración para revelar huecos en los criterios de aceptación y

descubrir riesgos en los que no se había pensado.

Los Test de Aceptación se pasan de forma correcta.

Los User Stories se pueden mostrar en la demo al Product Owner.

Se le puede avisar de los riesgos potenciales descubiertos durante la implementación y la exploración.

Se valida que se han cumplido los criterios de aceptación.

4 - DEMOSTRACIÓN

Page 162: TDD Course (Spanish)

AUTOMATIZACIÓN TEST DE ACEPTACIÓN

FIT / FITNESSE De las primeras, la más usada, potente y con soporte para muchos lenguajes.

Formato de especificación de los test muy poco natural.

FIT Tests escritos en HTML, ejecutados en línea de comandos.

La implementación se a portado a numerosos lenguajes de programación.

FITNESSE Utiliza FIT como motor de ejecución de las pruebas.

Web Server que muestra los test en formato Wiki.

Escrito en Java. El motor es FIT que soporta varios lenguajes (Java, C++ y .NET).

CONCORDION Empieza a desplazar a Fitnesse en un entorno java.

Escribir pruebas en lenguaje natural.

Sólo Java, conexión con test de JUnit.

CUCUMBER Aproximación BDD del ATDD (escenarios given/when/then) en lenguaje natural.

Ruby, con conexión a múltiples lenguajes: Java (JRuby), .NET (IRon Ruby), etc.

OTROS: Robot, Slim.

HERRAMIENTAS

Page 163: TDD Course (Spanish)

INTEGRACIÓN CONTINUA

INTEGRACIÓN CONTINUA

Page 164: TDD Course (Spanish)

If debugging is the process of removing software bugs,then programming must be the process of putting them in.

— Edsger Dijkstra

INTEGRACIÓN CONTINUA

Page 165: TDD Course (Spanish)

INTEGRACIÓN CONTINUA

Es una práctica de desarrollo de software.

No es una herramienta de automatización de integraciones. Práctica en la que cada desarrollador está obligado a realizar integraciones de su trabajo

con el resto del equipo de forma diaria, aunque tuviera que realizarse de forma manual.

No se necesitan herramientas específicas para practicar la integración continua.

Las herramientas de integración continua proporcionan el automatismo que alivia el esfuerzo de realizar estas integraciones de forma manual.

Aumentan la rapidez en la recepción de los feedbacks.

Práctica de desarrollo de software en la que los miembros del equipointegran su trabajo de forma frecuente, cada miembro del equiporealiza al menos una integración diaria de su trabajo, lo que permiteconseguir múltiples integraciones por día.

Cada integración se valida inmediatamente por un build automático,que incluye la ejecución de los tests, para detectar los errores deintegración tan pronto como sea posible.

Page 166: TDD Course (Spanish)

AUTOMATIZACIÓN DE LA INTEGRACIÓN CONTINUA

1. Checkout del proyecto desde el sistema de control de versiones (SCM).

2. Build de los módulos y ejecución de todos los tests unitarios para validar el funcionamiento de cada módulo de forma aislada.

3. Ejecución de tests de integración (sistema, aceptación, UI, etc.) para validar que la integración de los módulos se comporta de forma correcta.

4. Publicación de resultados de los test, informes, documentación, etc.

Page 167: TDD Course (Spanish)

AUTOMATIZACIÓN DE LA INTEGRACIÓN CONTINUA

Configuración de distintas tareas de build. La herramienta no suele estar encargada del proceso de build.

Delegación en herramientas de build: Make, Ant, NAnt, Maven, MSBuild, Rake, Shell, etc.

La herramienta puede proporcionar algunas características de integración con ciertas herramientas específicas de build. Ej. Localizar los módulos de un proyecto multimódulo, analizando el script o

configuración con las instrucciones del build.

El encargado de procesar la tarea es la herramienta de build.

La herramienta permite la configuración de tareas. El build puede generar lo que quiera el usuario.

Compilar, empaquetar, ejecutar tests, generar informes, generar documentación, desplegar en una máquina remota, etc.

El build debe estar planificado para permitir la generación independiente de diferentes objetivos: parámetros, perfiles, goals, tasks, etc.

CARACTERÍSTICAS

Page 168: TDD Course (Spanish)

AUTOMATIZACIÓN DE LA INTEGRACIÓN CONTINUA

Conexión con el sistema de control de versiones (SCM). Descargar el código de en desarrollo, ramas secundarias, versiones especificas, etc.

Lanzamiento automático de las tareas programadas. Ejecución cada vez que se detectan modificaciones en el SCM.

Ejecución cada cierto tiempo o en horas determinadas del día.

Control de máquinas remotas. Ejecución de los build en distintas máquinas de la red.

Despliegue remoto de las aplicaciones.

Recuperación de resultados y generación de informes. Los informes puede ser generados por la herramienta de build.

Las herramientas de integración continua reconocen diferentes formatos de diferentes resultados, generación específica de informes, localización de documentación, etc.

Ej. Los resultados en formato XML de las librerías xUnit usan un formato común.

Notificaciones Email, IM, SMS, etc.

CARACTERÍSTICAS

Page 169: TDD Course (Spanish)

AUTOMATIZACIÓN DE LA INTEGRACIÓN CONTINUA

Cruise Control

Cruise control.NET

Cruise control.rb

Cruise

CI Factory

Anthill

Continuum

Luntbuild

Hudson

...

HERRAMIENTAS

http://confluence.public.thoughtworks.org/display/CC/CI+Feature+Matrix: Matriz de características.http://www.javaworld.com/javaworld/jw-11-2006/jw-1101-ci.html: Análisis de cuatro herramientas importantes.

Page 170: TDD Course (Spanish)

INTEGRACIÓN CONTINUA

RAPID FEEDBACK Los problemas de integración se pueden detectar después de cada commit.

Notificaciones en el momento que se rompe la integración con otros módulos, lo que permite reaccionar y corregir el problema rápidamente.

AYUDA AL MANAGEMENT Herramienta para SCRUM MASTERS en el seguimiento del estado del proyecto a

través de los informes.

Informes de resultados de tests, cobertura de tests, avance en el cumplimiento en los tests de aceptación, etc.

EJECUCIÓN DE BATERIAS DE TEST PESADAS Ejecución periódica de tests lentos de alto nivel (sistema, UI, integración, etc.).

DISPONIBILIDAD DE DEMOS PERMANENTES Automatizar el despliegue y puesta en marcha de las aplicaciones en entornos

de desarrollo, maqueta o preprodución.

El cliente puede revisar en cualquier momento el grado de avance sobre la aplicación funcionando, o revisar los tests de aceptación, etc.

BENEFICIOS

Page 171: TDD Course (Spanish)

INTEGRACIÓN CONTINUA

Como norma nunca subir al SCM código que no funciona.

Código que no compila o que no pasa los tests unitarios.

El que rompe algo recibe la notificación y se responsabiliza de arreglarlo.

Intentar disponer siempre de una versión desplegable y ejecutable.

PELIGRO

La herramienta notifica inmediatamente de fallos en los tests.

NUNCA DESACTIVAR LOS TEST o eliminarlos para mantener libre de errores los informes de la herramienta de integración continua.

Se puede llevar el repositorio a una versión anterior mientras se reparan los problemas que impiden la disponibilidad de una integración.

RESPECT VALUE (XP)

Page 172: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

TEST DRIVEN DEVELOPMENTOBJETIVOS, BENEFICIOS, CARACTERÍSTICAS

Page 173: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

Asegura que el código de la aplicación se escribe para ser fácilmente testeable.

Asegura que existen test unitarios para cada característica codificada.

Resultados Inmediatos: Los desarrolladores comprueban los efectos de sus decisiones de diseño en minutos.

Flexibilidad y sencillez: Las modificaciones son sencillas debido a la pequeña escala de incrementos y poca distancia entre commits.

Batería automática de Tests de Regresión: Las modificaciones sobre un código desarrollado hace meses está protegida.

Se obtiene código bueno, limpio y que funciona.

Aumenta la calidad del software desarrollado.

OBJETIVOS, BENEFICIOS Y CARACTERÍSTICAS

Page 174: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

Código altamente reutilizable: El código que se escribe es mas modular, flexible y extensible. El desarrollador trata el software en incrementos muy reducidos, lo que dirige hacia clases pequeñas, mejor enfocadas, con acoplamiento más débil e interfaces más limpios.

Mejora el trabajo en equipo: Aumenta la confianza en nuestros compañeros, aunque tengan menos experiencia, multiplicando la comunicación entre los miembros del equipo.

Documentación en forma de ejemplos: ¿Qué hay mejor que un ejemplo de cómo se usa algo para saber como funciona?. Los tests no sustituyen la documentación, pero son un complemento importante.

Aumenta la productividad: El uso de TDD implica la escritura de más tests, y los programadores que escriben más tests tienden a ser más productivos. (*)

OBJETIVOS, BENEFICIOS Y CARACTERÍSTICAS

* Informe 2005, Ergodmus, Hakan; Morisio, Torchiano. "On the Effectiveness of Test-first Approach to Programming"

Page 175: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

Minimiza el uso del depurador: Los programadores que utilizan TDD informan que rara vez usan el depurador. Es más productivo volver atrás en el SCM que intentar depurar los fallos.

Aunque TDD implica escribir más código (tests y funcionalidad) el resultado es que el tiempo total de implementación se acorta.

OBJETIVOS, BENEFICIOS Y CARACTERÍSTICAS

Page 176: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

TEST DRIVEN DEVELOPMENTVULNERABILIDADES Y PELIGROS

Page 177: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

Más difícil de aplicar cuando se requiere una alta carga de test funcionales para determinar el éxito o fracaso.

Ej. Interfaces de usuario, acceso a base de datos, configuraciones de red.

Minimizar el código de los módulos difíciles de testear y maximizar la lógica en los módulos fácilmente testeables, usando mocks para representar el mundo exterior.

Toda la organización debe creer que TDD va a mejorar los desarrollos y productos. Gestores con la sensación de que se pierde el tiempo escribiendo tests.

Los tests se convierten en parte de la carga de mantenimiento. Los tests mal escritos se hacen caros de mantener.

RIESGO: Si los tests fallan a menudo serán ignorados en lugar de corregidos.

Se deben escribir tests que sean fáciles de mantener (refactoring).

VULNERABILIDADES Y PELIGROS

Page 178: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

El nivel de cobertura conseguido con TDD es difícil de recrear.

Los tests se convierten en una parte muy valiosa del proyecto.

En mantenimientos o nuevas versiones los tests se deben mantener.

Si se eliminan o desactivan, se obtendrán agujeros no detectables en la cobertura de tests.

Recuperar los tests en un momento posterior requerirá grandes esfuerzos.

Peligro de crear huecos inesperados en la cobertura de tests.

Si uno o más desarrolladores no aplican TDD.

Si se desactivan los tests con la intención de arreglarlos más tarde.

Si se modifica el código funcional y los tests fallan se deben arreglar de forma inmediata antes de dar por finalizado el mantenimiento.

VULNERABILIDADES Y PELIGROS

Page 179: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

Los test usados en TDD se codifican por los desarrolladores que escriben el código testeado.

Si el desarrollador malinterpreta los requisitos o no localiza las necesidades el código de los tests podría ser erróneo.

Tanto el código funcional como el código de los tests serán erróneos aunque los tests estén pasando correctamente.

El alto número de tests ejecutados correctamente puede inducir hacia una falsa sensación de seguridad. TDD no sustituye las técnicas tradicionales de testing.

La alta cobertura de test unitarios permite aligerar los tests de mayor nivel.

Pero se debe valorar y equilibrar correctamente la balanza.

VULNERABILIDADES Y PELIGROS

Page 180: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

TEST DRIVEN DEVELOPMENTMITOS Y MALENTENDIDOS

Page 181: TDD Course (Spanish)

MITO REALIDAD

TDD es una metodología de testing TDD es una metodología de desarrollo

TDD sustituye al trabajo de testing (QA) No sustituye al testing tradicional, el trabajo de QA sigue siendo necesario

Cobertura 100% en tests de regresión Componentes y frameworks de terceros sin cobertura de tests

Sistemas heredados sin cobertura de test

Dificultad para crear buena cobertura automatizando tests de interfaces de usuario (aun se depende de tests visuales de usuario)

Desarrolladores sin habilidades de testing adecuadas

No hay buen soporte para pruebas de regresión de bases de datos

Los test unitarios proporcionan el 100% del diseño y la especificación.

Los test unitarios proporcionan parte del diseño

Los test de aceptación proporcionan parte de la especificación

Tareas de diseño y especificación que no pueden ser totalmente cubiertas con el desarrollo TDD a través de tests unitarios

Sólo se necesitan tests unitarios Completamente falso, la comunidad Agile es clara en la necesidad de adoptar otras técnicas de testing

TDD es suficiente para cubrir el testing TDD dirige los desarrollos y proporciona una parte del testing, pero se requieren otros tests. Tests de sistema, integración, interfaz de usuario (visuales y automáticos), etc.

TDD no funciona en sistemas grandes Existen estadísticas de grandes proyectos desarrollados con TDD. Siempre se pueden dividir en unidades más pequeñas. TDD ataca directamente a la codificación en partes simples, sin importar el tamaño del sistema.

TDD – MITOS Y MALENTENDIDOS

Page 182: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT

APLICANDO TEST DRIVEN DEVELOPMENT¿CÓMO EMPEZAR?

Page 183: TDD Course (Spanish)

TDD - ¿CÓMO EMPEZAR?PEER PROGRAMMING: desarrolladores no formados en TDD. Equipos de trabajo donde no todos están formados en TDD. Practicar, al menos unos días, la programación por parejas. Desarrollador TDD con uno NO TDD para mostrar la dinámica de trabajo.

PROYECTOS QUE ESTÁN EN CURSO

Una locura intentar crear tests unitarios de todo el código existente. Vulnerabilidad: Costoso conseguir la cobertura de tests que habría dado TDD.

Si hay recursos e interesa, dedicar esfuerzos de QA (tests de integración).

La nueva funcionalidad (nuevas clases) se desarrolla con TDD.

Las modificaciones sobre código existente se realizan con TDD.

Si aparece un nuevo método se programan antes sus tests.

Si se localiza un bug, se escribe antes el test que lo hace fallar.

Si se modifica un método, se programa el test que valida exclusivamente la parte del código que se va a modificar, o la nueva característica.

Incrementalmente se consiguen tests unitarios sobre código existente, conforme se va necesitando. Recordar que TDD usa los tests para avanzar en el desarrollo.

Page 184: TDD Course (Spanish)

TDD - ¿CÓMO EMPEZAR?

NUEVOS PROYECTOS, MÓDULOS O SUBSISTEMAS

Todo el código a desarrollar es nuevo, se comienza desde cero.

Intentar aplicar durante el Sprint Planning las actividades propuestas por ATDD, para conseguir una especificación en forma de test de aceptación, y una especificación ejecutable.

Los tests de aceptación se pueden programar todos por adelantado o conforme se vayan seleccionando las tareas.

Una feature del product backlog pueden ser varios tests de aceptación.

Los tests de aceptación también ayudan a la identificación de tareas.

Se puede utilizar TDD sin utilizar ATDD (es independiente de la disponibilidad de test de aceptación).

TDD se debe convertir en la forma natural de programación.

Es bueno esbozar diseños preliminares, aunque no conviene dedicarles un tiempo excesivo (siguiendo los principios TDD), los diseños se pueden ir refinando conforme se avanzan los desarrollos y se recibe feedback.

Page 185: TDD Course (Spanish)

TDD - ¿CÓMO EMPEZAR?

DISPONEMOS DE UN DISEÑO Y ARQUITECTURA DETALLADA

Mejor imposible, ya tenemos una herramienta para localizar fácilmente por donde empezar.

Se selecciona una de las clases del diseño y se programa a través de la dirección de los test unitarios.

Los tests unitarios salen de la especificación del diseño.

Se pueden plantear construcciones bottom-up o top-down, pero conviene avanzar de forma paralela grupos de colaboraciones.

Recibir lo más rápido posible el feedback que se obtiene a través de la implementación del diseño, para decidir si hay que hacer ajustes en el diseño original (refactorización del diseño).

Los cambios en el diseño se podrán acometer con mínimo riesgo debido a la cobertura de test que se está consiguiendo.

Page 186: TDD Course (Spanish)

NECESITAMOS VUESTRO FEEDBACK

NECESITAMOS VUESTRO FEEDBACKSOBRE EL CURSO

Page 187: TDD Course (Spanish)

NECESITAMOS VUESTRO FEEDBACK

Creo que el curso ha durado demasiado.

Creo que el tiempo ha sido ajustado, debería durar más.

Creo que deberiais reducir los contenidos.

Creo que deberíais profundizar más en ciertas partes.

Prefiero no hacer ejercicios y que me expliquen las soluciones.

Prefiero hacer ejercicios antes de que me expliquen las soluciones.

Creo que hay errores en ciertas partes.

Esto no queda claro y deberíais explicarlo mejor.

No tengo ni idea de cómo ponerme ahora con TDD.

Necesito que alguien me ayude a empezar con cierta tecnología.

Etc.

Page 188: TDD Course (Spanish)

TEST DRIVEN DEVELOPMENT