48
Introducción al Test Driven Development

Introducción a tdd

Embed Size (px)

Citation preview

Introducción al

Test Driven

Development

Agenda

Fernando Pérez

[email protected]

@ferpega_

Juanjo Villar

[email protected]

@jj_villar

Introducción al software testing

Pruebas Unitarias

TDD (Fundamentos y patrones)

Kata FizzBuzz

TEORÍA

PRÁCTICA

Introducción

Software testing

Software testing - Introducción

¿Qué son las pruebas de software?

Forma automatizada de probar, empíricamente, que un software funciona

como se espera.

¿Qué ganamos realizando pruebas de software?

Fiabilidad, consistencia, eficiencia, mantenibilidad, mejor software y facilidad

para el refactoring. Pero sobre todo, dormir mucho mejor.

¿Qué precio debemos pagar?

• Diseñar nuestro software para que sea testable facilmente (altamente

cohesionado, bajamente acoplado, etc).

• Crear y mantener nuestros tests como si fuese código de producción.

Class Cohesion Revisited: http://www.iro.umontreal.ca/~sahraouh/qaoose/papers/Kabaili.pdf

Software testing - Tipos de Test

• Tests unitarios

Comprueban el correcto funcionamiento de la mínima unidad

de código posible (funcionalmente significativa).

• Tests de integración

Comprueban la interacción entre distintas entidades de nuestro

software.

• Tests de regresión

Aseguran la inmutabilidad del funcionamiento anterior a una

modificación.

• Tests de Sistema (end-to-end)

Prueban completamente un sistema integrado.

• Tests de aceptación

Prueban la funcionalidad (habitualmente desde el punto de vista

del usuario final).

Software testing - ¿Por qué es importante?

http://www.quora.com/What-is-software-unit-testing-and-why-is-it-important

Introducción

Pruebas unitarias

Pruebas unitarias - Introducción

Tests unitarios

• Muy útiles por el alcance de su prueba (muy concreto).

• Imprescindibles para el practicante de TDD

• Solo comprobarán uno de los comportamientos de un método de una clase.

• Suelen ser tests de “caja blanca”.

• Cumpliran los principios FIRST.

Pruebas unitarias - FIRST

Principios FIRST Descritos por Robert C. Martín (Uncle Bob) en su libro Clean Code.

Fast Deben ejecutarse muy rápido.

Isolated Único motivo de fallo, independientes del resto de test.

Repeatable Pueden ejecutarse n veces, siempre el mismo resultado.

Self-validating Resultado booleano y automático.

Timely Construido en el momento oportuno (en TDD antes del código)

Pruebas unitarias – Organización de proyectos

Organización de proyectos de Testing

• El proyecto de testing estará separado

del código de producción.

• Cada clase de test tendrá

correspondencia con una clase de

producción.

Pruebas unitarias - Atributos

Atributos MSTESTS

• Obligatorios

TestClass / TestMethod

• Excepciones

• Comprobaciones (Asserts)

[ExpectedException(typeof(System.DivideByZeroException))]

Assert.IsTrue(1 == 1);Assert.IsNull(null);Assert.AreEqual(2, 1 + 1);......

http://msdn.microsoft.com/en-

us/library/microsoft.visualstudio.testtools.unittesting.classinitializeattribute.classinitializeattribute.aspx

1 using Microsoft.VisualStudio.TestTools.UnitTesting;

2 3 namespace LibraryTddCourseTests4 {5 [TestClass]6 public class MyProductionClassTests7 {8 [AssemblyInitialize]9 public static void AssemblyInit(TestContext context) {}

10 11 [ClassInitialize]12 public static void ClassInit(TestContext context) {}13 14 [TestInitialize]15 public void Initialize() {}16 17 [TestMethod]18 public void TestMethod1() {}19 20 [TestCleanup]21 public void CleanUp() {}22 23 [ClassCleanup]24 public static void ClassCleanUp() { }25 26 [AssemblyCleanup]27 public static void AssemblyCleanup() { }28 }29 }

Pruebas unitarias – Ejecución de test

Desde el Test Explorer

• Denominados Test Runners

Pruebas unitarias – Partes de un test Unitario

• Arrange

Preparación del escenario a testear.

• Act

Acto de ejecución del código que va

a devolver el resultado a testear.

• Assert

Chequeo del resultado con las

comprobaciones de resultados.

// ArrangeMyProductionClass myProductionClass = new MyProductionClass();

// Actbool result = myProductionClass.GetBooleanResult();

// AssertAssert.IsTrue(result);

Test Driven Development

TODO CODIGO

FALLA

HASTA QUE SE

DEMUESTRE

LO CONTRARIO

TDD - Introducción

• Cuantas veces:

• Has empezado a desarrollar con especificaciones confusas

• Has descubierto, demasiado tarde, fallos en la especificación

• Has tenido un código totalmente fiable justo en el momento de terminarlo

• Has desarrollado más código del necesario

• Que nivel de estrés

• Te produce tocar un código desconocido

• Y un código de altas implicaciones/afecciones.

TDD - Introducción

TDD - Introducción

¿Qué ocurre cuando el nivel de estrés se eleva?

Circulo de retroalimentación:

“Kent Beck: Test Driven Development by Example”

¿Qué es? ¿ Cómo se hace? ¿Cómo me beneficia?

TDD

TDD - ¿Qué es?

• Escribir tests antes de escribir el código

• Testear antes como una actividad de diseño de software

• No testeamos para validar código, testeamos para diseñarlo

• Testear antes para evidenciar/clarificar qué debe hacer el código

TDD - Pasos

¿Qué queremos que haga el código que vamos a desarrollar?

¿Qué hechos demostrarán que nuestro código funciona?

TDD - Pasos

El test fallará

porque la función

todavía no existe

¿Escribimos el test?

Pensamos en el comportamiento del código y su interface público

TDD - Pasos

Escribimos el código de producción

SOLO el código necesario para pasar el test

TDD - Pasos

Refactorizamos la funcionalidad desarrollada

Durante la refactorización NO DEBEMOS cambiar la semántica (sentido)

TDD - Beneficios

• Código bajo completa especificación

• Ausencia de YAGNI (You aren’t gonna need it)

• KISS (Keep it simple, stupid). Código más simple y funcional. Se

persigue el objetivo

• Facilidad para aplicar principios SOLID

• Disminución del estrés, aumento de la confianza.

Patrones en Test Driven Development

TDD

Patrones para un buen TDD

Patrones TDD

Patrones para un buen TDD – Test List

• Realizar una lista de tests

• por funcionalidad/tarea/historia que debemos realizar

• con lo que debe ser y, también, lo que no debe ser

• si surgen nuevos tests o dudas, apuntarlos en la lista

Patrones para un buen TDD – Test First

• Escribir los tests antes del código

• romper el circulo de retroalimentación

• si se empiezan a escribir los tests después, se dejará de hacer

tests-first completamente.

• ayuda a definir:

• cual es la respuesta correcta

• cómo voy a chequearla

• donde pertenece esta funcionalidad

• como debería llamarla

Patrones para un buen TDD – Assert First

• Escribe tu Assert lo primero de todo

01 [TestMethod]02 public void CarTravelDistanceTest()03 {04 Assert.IsTrue(car.IsPowerOff());05 Assert.Equals(300, distance.FromStart());06 }

Queremos comprobar que el cuentakilómetros de un coche

mide correctamente.

Para obtener la medición final, el vehículo debe estar

apagado.

Recorremos una distancia concreta y obtenemos esa

distancia.

Patrones para un buen TDD – Assert First

• Escribe tu Assert lo primero de todo

• crece según sea necesario para alcanzar el objetivo

01 [TestMethod]02 public void CarTravelDistanceTest()03 {04 Distance distance = car.DistanceFromStart();05 Assert.IsTrue(car.IsPowerOff());06 Assert.Equals(300, distance.Kilometers());07 }

¿De donde sale la distancia?

Del cuenta kilómetros del propio vehículo, desde luego

Patrones para un buen TDD – Assert First

• Escribe tu Assert lo primero de todo

• crece según sea necesario para alcanzar el objetivo

¿Y el vehículo?

Lo creamos y debemos conducirlo a donde queremos ir

01 [TestMethod]02 public void CarTravelDistanceTest()03 {04 Car car = new Car("Opel", "blue");05 car.DriveTo("Bilbao");06 Distance distance = car.DistanceFromStart();07 Assert.IsTrue(car.IsPowerOff());08 Assert.Equals(300, distance.Kilometers());09 }

Patrones para un buen TDD – Test Data

• Usa información que sea fácil de leer

• Recuerda que escribes tests para una audiencia

• Minimiza los datos que usas

Si una lista de 3 elementos es suficiente, no pongas 10

• Como alternativa al “Test Data” está el “Realistic Data”, donde

usamos datos del mundo real.

Sistemas de tiempo real

Buscas equiparar salidas del sistema actual con el sistema

anterior

Estás refactorizando una simulación y se espera la misma

respuesta.

Patrones para un buen TDD – Evident Data

• Usa datos evidentes

• Estás escribiendo tests para otros, no para el ordenador

• Deja tantas pistas como sea posible

• Es posible que alguien esté leyendo tus tests el año que viene

• Y es posible que seas tu mismo

• Es preferible explicitar los cálculos:

Esto:Assert.Equals(300, distance.Kilometers());

Es peor que esto:Assert.Equals(1300 - 1000, distance.Kilometers());

Y peor que esto:Assert.Equals(PUNTO_KILOMETRICO_FINAL – PUNTO_KILOMETRICO_INICIAL, distance.Kilometers());

Patrones de barra roja (Red Bar Patterns)

Patrones TDD

Patrones de barra roja – Starter Test

• ¿Con cual de los tests de tu lista deberías empezar?• empieza por testear una variante de una operación que no haga nada

• a menudo un Starter Test es un test de alto nivel, como un test de

aplicación

var allAccounts = new IDictionary<Company, IList<Accounts>>();

Assert.AreEqual( 0, allCounts.SumAllAccounts());

Patrones de barra roja – One Step Test

• ¿Cual de los tests de tu lista es el siguiente a implementar?• uno que te enseñe algo del sistema

• sepas que puedes implementar sin problemas

• represente un paso hacía el objetivo global

No se sigue un desarrollo top-down o bottom-up.

Más bien se sigue un proceso de lo conocido a lo desconocido. Aprendiendo

por el camino.

Patrones de barra roja – Regression Test

• ¿Qué es lo primero que haces cuando un bug/defecto

es reportado?• escribe el menor test posible que falle por ese motivo

• una vez ejecutado el test y comprobado su fallo,

reparamos el bug

Patrones de barra roja – Explanation Test

• ¿Cómo difundir el uso de tests automatizados?• pide y da explicaciones en términos de tests

“Veamos si lo he entendido. Por ejemplo si tenemos Foo con este valor y

Bar con este otro, la respuesta debería ser X”

Patrones de barra verde (Green Bar Patterns)

Patrones TDD

Patrones de barra verde – Fake it (‘Til you make it)

• ¿Cuál es tu primera implementación para arreglar un test roto?

• devuelve justo lo necesario para arreglarlo y nada más

• seguramente una constante es suficiente. Gradualmente se

convertirá en una expresión u operación que usará variables =

abstracción.

Fake it causa mucha fricción en las personas. Sobre todo en programadores

experimentados.

¿Por qué hacer algo que sabes que tendrás que quitar?

¿Por qué hacer código que no durará ni una hora?

Porque es vital obtener un verde rápidamente y es mejor tener algo

funcionando que no tener nada o algo que falla.

Patrones de barra verde – Triangulate

• ¿Cuánto de conservador debo ser con la abstracción de los tests?

• abstrae solo cuando tengas dos o más ejemplos

Cuidado con entrar en lo que Kent Beck llama el bucle de triangulación.

[TestMethod]public void TestSum(){

Assert.Equals(4, Sum(3, 1));}

private int Sum(int x, int y){

return 4}

[TestMethod]public void TestSum(){

Assert.Equals(4, Sum(3, 1));Assert.Equals(5, Sum(3, 2));

}

private int Sum(int x, int y){

return x + y;}

[TestMethod]public void TestSum(){

Assert.Equals(4, Sum(3, 1));Assert.Equals(5, Sum(3, 2));

}

private int Sum(int x, int y){

return x + y;}

Patrones de barra verde – Obvious Implementation

• ¿Cómo implementas operaciones que, para ti, son simples?

• simplemente impleméntalas

Fake it y Triangulation son patrones de muy pequeños pasos.

Algunas veces ya sabes cómo se implementa una operación. Adelante!!!

Pero permanece atento a cuan a menudo recibes sorpresas en forma de

barras rojas usando Obvious y, si son demasiadas, vuelve al origen.

Ten en cuenta que Obvious es una “segunda marcha”. Vuelve a la primera en

cuanto “muerdas más de lo que puedes tragar”.

Patrones de barra verde – One to Many

• ¿Cómo implementas una operación que trabaja con colecciones?

• prepara el test y ponlo verde, sin la colección

01 [TestMethod]02 public void SumTest()03 {04 var result = Calculations.Sum(5);05 Assert.AreEqual(5, result);06 }

01 public static int Sum(int number)02 {03 return number;04 }

Patrones de barra verde – One to Many

• ¿Cómo implementas una operación que trabaja con colecciones?

• prepara el test y ponlo verde, sin la colección

01 [TestMethod]02 public void SumTest()03 {04 var result = Calculations.Sum(5, new int[] { 5 });05 Assert.AreEqual(5, result);06 }

01 public static int Sum(int number, int[] values)02 {03 return number;04 }

Patrones de barra verde – One to Many

• ¿Cómo implementas una operación que trabaja con colecciones?

• prepara el test y ponlo verde, sin la colección

01 [TestMethod]02 public void SumTest()03 {04 var result = Calculations.Sum(5, new int[] { 5 }));05 Assert.AreEqual(5, result);06 } 01 public static int Sum(int number, int[] values)

02 {03 int result = 0;04 for (int i = 0; i < values.Length; i++)05 {06 result += values[i];07 }08 return result;09 }

Patrones de barra verde – One to Many

• ¿Cómo implementas una operación que trabaja con colecciones?

• prepara el test y ponlo verde, sin la colección

06 [TestMethod]07 public void SumTest()08 {04 var result = Calculations.Sum(new int[] {3, 2 }));05 Assert.AreEqual(5, result);06 }

01 public static int Sum(int[] values)02 {03 int result = 0;04 for (int i = 0; i < values.Length; i++)05 {06 result += values[i];07 }08 return result;09 }