SlideShare una empresa de Scribd logo
1 de 91
AGENDA 
a Introducción al software testing 
a Pruebas Unitarias (Introducción, FIRST, Dobles) 
a Principios SOLID 
a TDD (Introducción, patrones y Visual Studio) 
a Inyección de dependencias
Software testing 
Introducción
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 / Introducción 
Tipos de Tests 
• 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).
Pruebas unitarias 
Introducción
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. 
Descritos por Robert C. Martín (Uncle Bob) en su libro Clean Code.
Pruebas unitarias / Introducción 
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 / Introducción 
Atributos MSTESTS 
• Obligatorios 
• TestClass / TestMethod 
• Excepciones 
[ExpectedException(typeof(System.DivideByZeroException))] 
• Comprobaciones (Asserts) 
1 using Microsoft.VisualStudio.TestTools.UnitTesting; 
2 
3 namespace LibraryTddCourseTests 
4 { 
5 [TestClass] 
6 public class MyProductionClassTests 
7 { 
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 } 
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
Pruebas unitarias / Introducción 
Ejecución de Tests 
• Desde el Test Explorer 
• Denominados Test Runners
Pruebas unitarias / Introducción 
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. 
// Arrange 
MyProductionClass myProductionClass = new MyProductionClass(); 
// Act 
bool result = myProductionClass.GetBooleanResult(); 
// Assert 
Assert.IsTrue(result);
Veamos un 
UNIT TEST
Pruebas unitarias 
F.I.R.S.T.
Pruebas unitarias / F.I.R.S.T. 
Tests unitarios 
• Fast 
Rápidos, muy rápidos 
Si no se ejecutan rápidamente, no son tests unitarios
Pruebas unitarias / F.I.R.S.T. 
Tests unitarios 
• Isolated (Independent) 
Solo tendrán una razón para fallar 
Independientes del resto de tests, no afectan al estado final del SUT 
El orden de ejecución no debe ser determinante 
Deben poder lanzarse en paralelo
Pruebas unitarias / F.I.R.S.T. 
Tests unitarios 
• Repeatable 
Repetibles, pueden ejecutarse cuantas veces se desee ofreciendo siempre el mismo 
resultado.
Pruebas unitarias / F.I.R.S.T. 
Tests unitarios 
• Self-Validating 
De resultado booleano (no logs, no DB, etc). 
Automático (no requiere comprobación manual).
Pruebas unitarias / F.I.R.S.T. 
Tests unitarios 
• Timely 
Serán construidos en el momento oportuno, preferiblemente antes del código que 
tratan de testear. 
Debemos saber qué queremos construir con antelación.
Pruebas unitarias 
Dobles (Tests Doubles)
Dobles/ Escenario 
¿Y si una clase tiene dependencias? 
Si tiene dependencias y testeamos también esas dependencias, ¿seguro que es un 
test de unidad? 
¿Y si una de nuestras dependencias tiene problemas? 
Nuestro test fallará. Pero… 
¿Realmente es un problema de nuestro código? 
¿Podemos solucionar el problema o está fuera de nuestra capacidad? 
¿Y si el problema es aleatorio o la dependencia es pesada? 
Dobles al rescate
Dobles / Escenario 
SUT
Dobles / Escenario 
SUT 
Punto de fallo 
Punto de fallo
Dobles / Escenario 
SUT
Dobles / Introducción 
¿Qué son? 
Objetos falsos que reemplazan a los verdaderos con el objeto de eliminar su 
dependencia y poder hacer tests con comodidad. 
¿En que consiste? 
En crear falsas clases que tendrán respuestas pre-determinadas y que inyectaremos a 
nuestro SUT. 
¿Cómo podemos hacer esto? 
Manualmente o con ‘Isolation Frameworks’ (frameworks de mocking)
Dobles / Introducción 
¿Distintos tipos de tests doubles? 
Hay una fina línea que los diferencia que depende del autor. 
• Dummy 
Objetos que son pasados como relleno de dependencias. Nunca son usados. 
• Fake 
Objetos que tienen una implementación funcional pero con atajos que les impiden ser viables para 
usarse en entornos de producción (una base de datos en memoria, por ejemplo). 
• Stubs 
Objetos que se preparan para ofrecer respuestas concretas a peticiones concretas. Pueden usar 
verificación de estado (Assert). 
• Mocks 
Objetos sobre los que se tiene algún tipo de expectativa. Tienen Asserts que verifican 
comportamiento.
Dobles / Ejemplo
Dobles / Ejemplo 
01 public class CustomerService 
02 { 
03 private ICustomerRepository _customerRepository; 
04 private IComplaintRepository _complaintRepository; 
05 private ICustomerCareNotificationService _customercareNotificationService; 
06 
07 public CustomerService(ICustomerRepository customerRepository, 
08 IComplaintRepository complaintRepository, 
09 ICustomerCareNotificationService customerCareNotificationService) 
10 { 
11 this._customerRepository = customerRepository; 
12 this._complaintRepository = complaintRepository; 
13 this._customercareNotificationService = customerCareNotificationService; 
14 } 
15 
16 public List<string> Complaints(int clientId) 
17 { 
18 var complaints = _complaintRepository.GetAllFromClientId(clientId); 
19 
20 bool isAVipCustomer = _customerRepository.GetCustomerCategory(clientId); 
21 if (isAVipCustomer) 
22 SendNotificationToCustomerCare(clientId); 
23 
24 var result = complaints.Select(c => c.Title); 
25 
26 return result.ToList(); 
27 } 
28 
29 private void SendNotificationToCustomerCare(int clientId) 
30 { 
31 this._customercareNotificationService.SendNotificationAboutVipCustomerComplaint(clientId); 
32 } 
33 }
Hagamos los tests 
de ejemplo con Dobles
SOLID Principles 
Introducción
SOLID / Introducción 
Serie de principios de desarrollo en programación orientada a objetos 
Originalmente recopilados por Robert C. Martín en 1995 
Proporcionan un camino para conseguir código bajamente acoplado, 
altamente cohesivo que encapsule las necesidades de negocio correctamente
SOLID / Introducción 
No es un framework 
No es una librería 
No son unos patrones 
No son un objetivo 
Son unos principios de diseño orientado a objetos 
Son un medio para conseguir código desacoplado 
Y por tanto un modo de hacer código más mantenible
SOLID Principles
SOLID
SOLID / Single Responsibility Principle (SRP) 
“Una clase debería tener una, y solo una, razón para cambiar ” 
Una clase debería tener una única responsabilidad. 
Podemos aplicarlo también a los métodos de la clase. 
Beneficios 
Proporciona un código más desacoplado y más fácil de mantener. 
Proporciona unas clases más pequeñas y limpias.
SOLID / Single Responsibility Principle (SRP) 
1 public class Reception 
2 { 
3 private string _receptionistName = "Peter"; 
4 public string GetGreeting() 
5 { 
6 return string.Format("You are Welcome, my name is {0}", _receptionistName); 
7 } 
8 
9 public string GetRoomKeys() 
10 { 
11 return "room 101"; 
12 } 
13 
14 public string PrintInvoce(string roomKeys) 
15 { 
16 return string.Format("Your invoice for {0}", roomKeys); 
17 } 
18 }
SOLID / Single Responsibility Principle (SRP) 
1 public class Reception 
2 { 
3 private string _receptionistName = "Peter"; 
4 public string GetGreeting() 
5 { 
6 return string.Format("You are Welcome, my name is {0}", _receptionistName); 
7 } 
8 
9 public string GetRoomKeys() 
10 { 
11 return "room 101"; 
12 } 
13 
14 public string PrintInvoce(string roomKeys) 
15 { 
16 return string.Format("Your invoice for {0}", roomKeys); 
17 } 
18 }
SOLID - SRP
SOLID / Single Responsibility Principle (SRP) 
1 public class Reception 
2 { 
3 private string _receptionistName = "Peter"; 
4 private RoomService _roomService = new RoomService(); 
5 private InvoicePrinter _invoicePrinter = new InvoicePrinter(); 
6 public string GetGreeting() 
7 { 
8 return string.Format("You are Welcome, my name is {0}", _receptionistName); 
9 } 
10 
11 public string GetRoomKeys() 
12 { 
13 return _roomService.GetFreeRoom(); 
14 } 
15 
16 public string PrintInvoce(string roomKeys) 
17 { 
18 return _invoicePrinter.Print(roomKeys); 
19 } 
20 }
SOLID / Open-Closed Principle (OCP) 
“Una clase debería estar abierta a extensión pero cerrada a modificación” 
Deberíamos poder cambiar o extender el comportamiento de una clase, sin 
modificarla en absoluto. 
Beneficios 
Podemos añadir nueva funcionalidad sin dañar el código existente
SOLID / Open-Closed Principle (OCP) 
1 public class Reception 
2 { 
3 private string _receptionistName = "Peter"; 
4 private RoomService _roomService = new RoomService(); 
5 private InvoicePrinter _invoicePrinter = new InvoicePrinter(); 
6 
7 public string GetGreeting() 
8 { 
9 return string.Format("You are Welcome, my name is {0}", _receptionistName); 
10 } 
11 
12 public string GetRoomKeys() 
13 { 
14 return _roomService.GetFreeRoom(); 
15 } 
16 
17 public string PrintInvoce(string roomKeys) 
18 { 
19 return _invoicePrinter.Print(roomKeys); 
20 } 
21 } 
1 public class InvoicePrinter 
2 { 
3 public string Print(string roomKeys) 
4 { 
5 return string.Format("Your invoice for room {0}", roomKeys); 
6 } 
7 }
SOLID - OCP
SOLID / Open-Closed Principle (OCP) 
1 public class Reception 
2 { 
3 private string _receptionistName = "Peter"; 
4 private RoomService _roomService = new RoomService(); 
5 private InvoicePrinter _invoicePrinter = new InvoiceTextPrinter(); 
6 
7 public string GetGreeting() 
8 { 
9 return string.Format("You are Welcome, my name is {0}", _receptionistName); 
10 } 
11 
12 public string GetRoomKeys() 
13 { 
14 return _roomService.GetFreeRoom(); 
15 } 
16 
17 public string PrintInvoce(string roomKeys) 
18 { 
19 return _invoicePrinter.Print(roomKeys); 
20 } 
21 } 
1 public abstract class InvoicePrinter 
2 { 
3 public abstract string Print(string roomKeys); 
4 }
SOLID / Open-Closed Principle (OCP) 
1 public class Reception 
2 { 
3 private string _receptionistName = "Peter"; 
4 private RoomService _roomService = new RoomService(); 
5 private InvoicePrinter _invoicePrinter = new InvoiceHtmlPrinter(); 
6 
7 public string GetGreeting() 
8 { 
9 return string.Format("You are Welcome, my name is {0}", _receptionistName); 
10 } 
11 
12 public string GetRoomKeys() 
13 { 
14 return _roomService.GetFreeRoom(); 
15 } 
16 
17 public string PrintInvoce(string roomKeys) 
18 { 
19 return _invoicePrinter.Print(roomKeys); 
20 } 
21 } 
1 public abstract class InvoicePrinter 
2 { 
3 public abstract string Print(string roomKeys); 
4 }
SOLID / Liskov Substitution Principle (LSP) 
“Sustituir un objeto por una subclase de ese objeto no debería cambiar el 
comportamiento o el buen funcionamiento del programa (o de su clase base)” 
Si una función recibe un objeto como parámetro, de tipo X y en su lugar le 
pasamos otro de tipo Y, que hereda de X, dicha función debe proceder 
correctamente. 
Una función que no cumple LSP, habitualmente rompe OCP, pues necesita 
saber demasiado de la clase ancestro para poder modificar su funcionamiento.
SOLID / Liskov Substitution Principle (LSP) 
1 static void Main(string[] args) 
2 { 
3 // Management 
4 InvoiceCalculator invoiceCalculator = new InvoiceCalculator(); 
5 invoiceCalculator.Base = 1000m; 
6 invoiceCalculator.IVA = 0.21m; 
7 
8 var printerForReception = new InvoiceTextPrinter(); 
9 var reception = new Reception(); 
10 
11 // Customer 
12 Console.WriteLine(reception.GetGreeting()); 
13 var roomKeys = reception.GetRoomKeys(); 
14 
15 Console.WriteLine(printerForReception.Print(roomKeys, invoiceCalculator)); 
16 
17 Console.ReadKey(); 
18 }
SOLID / Liskov Substitution Principle (LSP) 
1 static void Main(string[] args) 
2 { 
3 // Management 
4 InvoiceCalculator invoiceCalculator = new InvoiceForeignCalculator(); 
5 invoiceCalculator.Base = 1000m; 
6 invoiceCalculator.IVA = 0.21m; 
7 
8 var printerForReception = new InvoiceTextPrinter(); 
9 var reception = new Reception(); 
10 
11 // Customer 
12 Console.WriteLine(reception.GetGreeting()); 
13 var roomKeys = reception.GetRoomKeys(); 
14 
15 Console.WriteLine(printerForReception.Print(roomKeys, invoiceCalculator)); 
16 
17 Console.ReadKey(); 
18 }
SOLID / Liskov Substitution Principle (LSP) 
Cuando un grupo de clases incumple LSP, es muy habitual que el problema 
subyacente resida en el diseño y que la única solución sea un rediseño 
completo de la jerarquía de clases.
SOLID - LSP
SOLID / Liskov Substitution Principle (LSP) 
1 class Program 
2 { 
3 static void Main(string[] args) 
4 { 
5 // Management 
6 InvoiceCalculator invoiceCalculator = new InvoiceLocalCalculator(1000m, 0.21m); 
7 InvoiceCalculator invoiceCalculator = new InvoiceForeignCalculator(1000m); 
8 
9 var printerForReception = new InvoiceTextPrinter(); 
10 var reception = new Reception(); 
11 
12 // Customer 
13 Console.WriteLine(reception.GetGreeting()); 
14 var roomKeys = reception.GetRoomKeys(); 
15 
16 Console.WriteLine(printerForReception.Print(roomKeys, invoiceCalculator)); 
17 
18 Console.ReadKey(); 
19 } 
20 }
SOLID / Interface Segregation Principle (ISP) 
“Una clase cliente no debe ser forzada a depender de un interface que no 
necesita” 
Si una clase cliente usa un interface con más métodos de los que ella misma 
necesita es muy probable que ese interface sirva a varias clases cliente con 
responsabilidades diferentes. 
ISP y SRP están muy ligados. Un buen SRP habitualmente implica un buen ISP.
SOLID / Interface Segregation Principle (ISP) 
1 public class Receptionist : IStaff 
2 { 
3 private string _name; 
4 public Receptionist(string name) 
5 { 
6 this._name = name; 
7 } 
8 
9 public string GetName() 
10 { 
11 return _name; 
12 } 
13 public string GetDrink(string drinkName) 
14 { 
15 throw new NotImplementedException(); 
16 } 
17 public bool CheckReservation(string clientName) 
18 { 
19 return true; 
20 } 
21 } 
1 public class Reception 
2 { 
3 ... 
6 
11 public string GetDrink() 
12 { 
13 return _receptionist.GetDrink("gin tonic"); 
14 }
SOLID - ISP
SOLID / Interface Segregation Principle (ISP)
SOLID / Dependency Inversion Principle (DIP) 
“Módulos de alto nivel no deberían depender de módulos de bajo nivel. 
Ambos deberían depender de abstracciones” 
“Abstracciones no deberían depender de los detalles. Los detalles deberían 
depender de las abstracciones” 
Una clase padre, accederá a sus dependencias a través de interfaces o clases 
abstractas. 
Diseñaremos nuestro sistema de arriba hacia abajo, no al revés.
SOLID / Dependency Inversion Principle (DIP)
SOLID - DIP
SOLID / Dependency Inversion Principle (DIP) 
Cumplimos el primer punto del Principio de 
Inversión de Dependencia
SOLID / Dependency Inversion Principle (DIP) 
Cumplimos los dos puntos 
del Principio
Test Driven 
Development 
Introducción
TDD / Introducción 
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 
¿Qué ocurre cuando el nivel de estrés se eleva? 
Circulo de retroalimentación: 
“Kent Beck: Test Driven Development by Example”
TDD 
¿Qué es? ¿Cómo se hace? ¿Cómo me beneficia?
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.
TDD 
Patrones de Test Driven Development
TDD / Patrones para un buen TDD / Tests 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
TDD / Patrones para un buen TDD / Tests 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
TDD / Patrones para un buen TDD / Assert First 
• Escribe tu Assert lo primero de todo 
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. 
01 [TestClass] 
02 public void CarTravelDistanceTest() 
03 { 
04 Assert.IsTrue(car.IsPowerOff()); 
05 Assert.Equals(300, distance.FromStart()); 
06 }
TDD / Patrones para un buen TDD / Assert First 
• Escribe tu Assert lo primero de todo 
• crece según sea necesario para alcanzar el objetivo 
¿De donde sale la distancia? 
Del cuenta kilómetros del propio vehículo, desde luego 
01 [TestClass] 
02 public void CarTravelDistanceTest() 
03 { 
04 Distance distance = car.DistanceFromStart(); 
05 Assert.IsTrue(car.IsPowerOff()); 
06 Assert.Equals(300, distance.Kilometers()); 
07 }
TDD / 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 01 [TestClass] debemos conducirlo a donde queremos ir 
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 }
TDD / 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. 
• Sobre todo si la precisión de coma flotante puede ser un problema.
TDD / 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());
TDD 
Patrones de barra roja (Red Bar Patterns)
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 
var allAccounts = new IDictionary<Company, IList<Accounts>>(); 
Assert.AreEqual( 0, allCounts.SumAllAccounts()); 
• a menudo un Starter Test es un test de alto nivel, como un test de aplicación
TDD / 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.
TDD / 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”
TDD / 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
TDD 
Patrones de barra verde (Green Bar Patterns)
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) 
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? 
Porque es vital obtener un verde rápidamente y es mejor tener algo 
funcionando que no tener nada o algo que falla.
TDD / 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 podemos denominar como el bucle de 
triangulación. 
[TestMeethod] 
public void TestSum() 
{ 
Assert.Equals(4, Sum(3, 1)); 
} 
private int Sum(int x, int y) 
{ 
return 4 
} 
[TestMeethod] 
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; 
} 
[TestMeethod] 
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; 
}
TDD / 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 ”.
TDD / 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 [TestClass] 
02 public void SumTest() 
03 { 
04 Assert.AreEqual(5, Calculations.Sum(5)); 
05 } 
01 public static int Sum(int number) 
02 { 
03 return number; 
04 }
TDD / 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 [TestClass] 
02 public void SumTest() 
03 { 
04 Assert.AreEqual(5, Calculations.Sum(5, new int[] { 5 })); 
05 } 
01 public static int Sum(int number, int[] values) 
02 { 
03 return number; 
04 }
TDD / 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 [TestClass] 
02 public void SumTest() 
03 { 
04 Assert.AreEqual(5, Calculations.Sum(5, new int[] { 5 })); 
05 } 
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 }
TDD / 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 [TestClass] 
07 public void SumTest() 
08 { 
09 Assert.AreEqual(5, Calculations.Sum(new int[] { 3, 2 })); 
10 } 
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 }
SEATTLE 
www.plainconcepts.com 
MADRID 
General Rodrigo 6 
Cuerpo alto, 1ª planta 
28003 
(+34) 915 346 836 
BILBAO 
Nervión 3 
6ª planta 
48001 
(+34) 946 008 168 
1511 Third Avenue 
Suite 512 
WA 98101 
(+1) 206 708 1285 
SEVILLA 
Avd. Innovación 3 
Hércules, 3º planta, modulo 4 
41020 
(+34) 955 222 906

Más contenido relacionado

La actualidad más candente

Top 50 Software Testing Interview Questions & Answers | Edureka
Top 50 Software Testing Interview Questions & Answers | EdurekaTop 50 Software Testing Interview Questions & Answers | Edureka
Top 50 Software Testing Interview Questions & Answers | EdurekaEdureka!
 
Qa exploratory test charter template
Qa exploratory test charter templateQa exploratory test charter template
Qa exploratory test charter templateRob Swoboda
 
Unit Test Presentation
Unit Test PresentationUnit Test Presentation
Unit Test PresentationSayedur Rahman
 
Test Driven Development With Python
Test Driven Development With PythonTest Driven Development With Python
Test Driven Development With PythonSiddhi
 
Cypress en un mundo lleno de Selenium
Cypress en un mundo lleno de SeleniumCypress en un mundo lleno de Selenium
Cypress en un mundo lleno de SeleniumSoftware Guru
 
Software Testing Basic Concepts
Software Testing Basic ConceptsSoftware Testing Basic Concepts
Software Testing Basic Conceptswesovi
 
Unit tests & TDD
Unit tests & TDDUnit tests & TDD
Unit tests & TDDDror Helper
 
Basic Guide to Manual Testing
Basic Guide to Manual TestingBasic Guide to Manual Testing
Basic Guide to Manual TestingHiral Gosani
 
Agile test-management-test-rail-lastest
Agile test-management-test-rail-lastestAgile test-management-test-rail-lastest
Agile test-management-test-rail-lastestOnur Baskirt
 
TESTING LIFE CYCLE PPT
TESTING LIFE CYCLE PPTTESTING LIFE CYCLE PPT
TESTING LIFE CYCLE PPTsuhasreddy1
 
Enterprise Software Architecture styles
Enterprise Software Architecture stylesEnterprise Software Architecture styles
Enterprise Software Architecture stylesAraf Karsh Hamid
 
Software Testing Basics
Software Testing BasicsSoftware Testing Basics
Software Testing BasicsBelal Raslan
 
TDD - Test Driven Development
TDD - Test Driven DevelopmentTDD - Test Driven Development
TDD - Test Driven DevelopmentTung Nguyen Thanh
 
Understanding Unit Testing
Understanding Unit TestingUnderstanding Unit Testing
Understanding Unit Testingikhwanhayat
 
An introduction to unit testing
An introduction to unit testingAn introduction to unit testing
An introduction to unit testingAdam Stephensen
 

La actualidad más candente (20)

Top 50 Software Testing Interview Questions & Answers | Edureka
Top 50 Software Testing Interview Questions & Answers | EdurekaTop 50 Software Testing Interview Questions & Answers | Edureka
Top 50 Software Testing Interview Questions & Answers | Edureka
 
Qa exploratory test charter template
Qa exploratory test charter templateQa exploratory test charter template
Qa exploratory test charter template
 
Unit Test Presentation
Unit Test PresentationUnit Test Presentation
Unit Test Presentation
 
Workshop unit test
Workshop   unit testWorkshop   unit test
Workshop unit test
 
Test Driven Development With Python
Test Driven Development With PythonTest Driven Development With Python
Test Driven Development With Python
 
Cypress en un mundo lleno de Selenium
Cypress en un mundo lleno de SeleniumCypress en un mundo lleno de Selenium
Cypress en un mundo lleno de Selenium
 
TDD - Agile
TDD - Agile TDD - Agile
TDD - Agile
 
Software Testing Basic Concepts
Software Testing Basic ConceptsSoftware Testing Basic Concepts
Software Testing Basic Concepts
 
Unit testing
Unit testingUnit testing
Unit testing
 
Unit tests & TDD
Unit tests & TDDUnit tests & TDD
Unit tests & TDD
 
50 Soruda Yazılım Testi
50 Soruda Yazılım Testi50 Soruda Yazılım Testi
50 Soruda Yazılım Testi
 
Basic Guide to Manual Testing
Basic Guide to Manual TestingBasic Guide to Manual Testing
Basic Guide to Manual Testing
 
Agile test-management-test-rail-lastest
Agile test-management-test-rail-lastestAgile test-management-test-rail-lastest
Agile test-management-test-rail-lastest
 
TESTING LIFE CYCLE PPT
TESTING LIFE CYCLE PPTTESTING LIFE CYCLE PPT
TESTING LIFE CYCLE PPT
 
Test Automation - Keytorc Approach
Test Automation - Keytorc Approach Test Automation - Keytorc Approach
Test Automation - Keytorc Approach
 
Enterprise Software Architecture styles
Enterprise Software Architecture stylesEnterprise Software Architecture styles
Enterprise Software Architecture styles
 
Software Testing Basics
Software Testing BasicsSoftware Testing Basics
Software Testing Basics
 
TDD - Test Driven Development
TDD - Test Driven DevelopmentTDD - Test Driven Development
TDD - Test Driven Development
 
Understanding Unit Testing
Understanding Unit TestingUnderstanding Unit Testing
Understanding Unit Testing
 
An introduction to unit testing
An introduction to unit testingAn introduction to unit testing
An introduction to unit testing
 

Similar a Introducción a Unit Testing y TDD

DeSymfonyDay 2014 - To mock or not to mock - Spanish
DeSymfonyDay 2014 - To mock or not to mock - SpanishDeSymfonyDay 2014 - To mock or not to mock - Spanish
DeSymfonyDay 2014 - To mock or not to mock - SpanishJordi Llonch
 
DeSymfonyDay 2014 - To mock or not to mock - Spanish
DeSymfonyDay 2014 - To mock or not to mock - SpanishDeSymfonyDay 2014 - To mock or not to mock - Spanish
DeSymfonyDay 2014 - To mock or not to mock - SpanishJordi Llonch
 
DeSymfonyDay 2014 - To mock or not to mock - Spanish
DeSymfonyDay 2014 - To mock or not to mock - SpanishDeSymfonyDay 2014 - To mock or not to mock - Spanish
DeSymfonyDay 2014 - To mock or not to mock - SpanishAkamon Engineering
 
Junit y Jmock
Junit y JmockJunit y Jmock
Junit y Jmockkaolong
 
Pruebas de aceptación 15 11_2013
Pruebas de aceptación 15 11_2013Pruebas de aceptación 15 11_2013
Pruebas de aceptación 15 11_2013dayaorte
 
Artalde Tdd intro
Artalde Tdd introArtalde Tdd intro
Artalde Tdd introfperezplain
 
Unit Testing - GTUG
Unit Testing - GTUGUnit Testing - GTUG
Unit Testing - GTUGJordi Gerona
 
Unit Testing - Trovit
Unit Testing - TrovitUnit Testing - Trovit
Unit Testing - TrovitJordi Gerona
 
Buenas prácticas para la construcción de software
Buenas prácticas para la construcción de softwareBuenas prácticas para la construcción de software
Buenas prácticas para la construcción de softwareIker Canarias
 
Insight Brou 2009 11 Encuentro Usr Rational Gur07
Insight Brou 2009 11   Encuentro Usr Rational Gur07Insight Brou 2009 11   Encuentro Usr Rational Gur07
Insight Brou 2009 11 Encuentro Usr Rational Gur07Irene Pazos Viana
 
Testing efectivo con pytest
Testing efectivo con pytestTesting efectivo con pytest
Testing efectivo con pytestHector Canto
 
Unit Testing with Mock Objects
Unit Testing with Mock ObjectsUnit Testing with Mock Objects
Unit Testing with Mock ObjectsAngel Nuñez
 
Pruebas Automatizadas
Pruebas AutomatizadasPruebas Automatizadas
Pruebas AutomatizadasAngel Nuñez
 
Pruebas de software
Pruebas de softwarePruebas de software
Pruebas de softwareGomez Gomez
 

Similar a Introducción a Unit Testing y TDD (20)

Test unitarios
Test unitariosTest unitarios
Test unitarios
 
DeSymfonyDay 2014 - To mock or not to mock - Spanish
DeSymfonyDay 2014 - To mock or not to mock - SpanishDeSymfonyDay 2014 - To mock or not to mock - Spanish
DeSymfonyDay 2014 - To mock or not to mock - Spanish
 
DeSymfonyDay 2014 - To mock or not to mock - Spanish
DeSymfonyDay 2014 - To mock or not to mock - SpanishDeSymfonyDay 2014 - To mock or not to mock - Spanish
DeSymfonyDay 2014 - To mock or not to mock - Spanish
 
DeSymfonyDay 2014 - To mock or not to mock - Spanish
DeSymfonyDay 2014 - To mock or not to mock - SpanishDeSymfonyDay 2014 - To mock or not to mock - Spanish
DeSymfonyDay 2014 - To mock or not to mock - Spanish
 
Introducción a tdd
Introducción a tddIntroducción a tdd
Introducción a tdd
 
Junit y Jmock
Junit y JmockJunit y Jmock
Junit y Jmock
 
Pruebas de aceptación 15 11_2013
Pruebas de aceptación 15 11_2013Pruebas de aceptación 15 11_2013
Pruebas de aceptación 15 11_2013
 
Tdd
TddTdd
Tdd
 
Artalde Tdd intro
Artalde Tdd introArtalde Tdd intro
Artalde Tdd intro
 
Qunit CookBook español
Qunit CookBook españolQunit CookBook español
Qunit CookBook español
 
Unit Testing - GTUG
Unit Testing - GTUGUnit Testing - GTUG
Unit Testing - GTUG
 
Unit Testing - Trovit
Unit Testing - TrovitUnit Testing - Trovit
Unit Testing - Trovit
 
Testing 101 con Arquillian
Testing 101 con ArquillianTesting 101 con Arquillian
Testing 101 con Arquillian
 
Testeo unitario
Testeo unitarioTesteo unitario
Testeo unitario
 
Buenas prácticas para la construcción de software
Buenas prácticas para la construcción de softwareBuenas prácticas para la construcción de software
Buenas prácticas para la construcción de software
 
Insight Brou 2009 11 Encuentro Usr Rational Gur07
Insight Brou 2009 11   Encuentro Usr Rational Gur07Insight Brou 2009 11   Encuentro Usr Rational Gur07
Insight Brou 2009 11 Encuentro Usr Rational Gur07
 
Testing efectivo con pytest
Testing efectivo con pytestTesting efectivo con pytest
Testing efectivo con pytest
 
Unit Testing with Mock Objects
Unit Testing with Mock ObjectsUnit Testing with Mock Objects
Unit Testing with Mock Objects
 
Pruebas Automatizadas
Pruebas AutomatizadasPruebas Automatizadas
Pruebas Automatizadas
 
Pruebas de software
Pruebas de softwarePruebas de software
Pruebas de software
 

Introducción a Unit Testing y TDD

  • 1.
  • 2. AGENDA a Introducción al software testing a Pruebas Unitarias (Introducción, FIRST, Dobles) a Principios SOLID a TDD (Introducción, patrones y Visual Studio) a Inyección de dependencias
  • 4. 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
  • 5. Software testing / Introducción Tipos de Tests • 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).
  • 7. 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. Descritos por Robert C. Martín (Uncle Bob) en su libro Clean Code.
  • 8. Pruebas unitarias / Introducción 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.
  • 9. Pruebas unitarias / Introducción Atributos MSTESTS • Obligatorios • TestClass / TestMethod • Excepciones [ExpectedException(typeof(System.DivideByZeroException))] • Comprobaciones (Asserts) 1 using Microsoft.VisualStudio.TestTools.UnitTesting; 2 3 namespace LibraryTddCourseTests 4 { 5 [TestClass] 6 public class MyProductionClassTests 7 { 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 } 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
  • 10. Pruebas unitarias / Introducción Ejecución de Tests • Desde el Test Explorer • Denominados Test Runners
  • 11. Pruebas unitarias / Introducción 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. // Arrange MyProductionClass myProductionClass = new MyProductionClass(); // Act bool result = myProductionClass.GetBooleanResult(); // Assert Assert.IsTrue(result);
  • 14. Pruebas unitarias / F.I.R.S.T. Tests unitarios • Fast Rápidos, muy rápidos Si no se ejecutan rápidamente, no son tests unitarios
  • 15. Pruebas unitarias / F.I.R.S.T. Tests unitarios • Isolated (Independent) Solo tendrán una razón para fallar Independientes del resto de tests, no afectan al estado final del SUT El orden de ejecución no debe ser determinante Deben poder lanzarse en paralelo
  • 16. Pruebas unitarias / F.I.R.S.T. Tests unitarios • Repeatable Repetibles, pueden ejecutarse cuantas veces se desee ofreciendo siempre el mismo resultado.
  • 17. Pruebas unitarias / F.I.R.S.T. Tests unitarios • Self-Validating De resultado booleano (no logs, no DB, etc). Automático (no requiere comprobación manual).
  • 18. Pruebas unitarias / F.I.R.S.T. Tests unitarios • Timely Serán construidos en el momento oportuno, preferiblemente antes del código que tratan de testear. Debemos saber qué queremos construir con antelación.
  • 19. Pruebas unitarias Dobles (Tests Doubles)
  • 20. Dobles/ Escenario ¿Y si una clase tiene dependencias? Si tiene dependencias y testeamos también esas dependencias, ¿seguro que es un test de unidad? ¿Y si una de nuestras dependencias tiene problemas? Nuestro test fallará. Pero… ¿Realmente es un problema de nuestro código? ¿Podemos solucionar el problema o está fuera de nuestra capacidad? ¿Y si el problema es aleatorio o la dependencia es pesada? Dobles al rescate
  • 22. Dobles / Escenario SUT Punto de fallo Punto de fallo
  • 24. Dobles / Introducción ¿Qué son? Objetos falsos que reemplazan a los verdaderos con el objeto de eliminar su dependencia y poder hacer tests con comodidad. ¿En que consiste? En crear falsas clases que tendrán respuestas pre-determinadas y que inyectaremos a nuestro SUT. ¿Cómo podemos hacer esto? Manualmente o con ‘Isolation Frameworks’ (frameworks de mocking)
  • 25. Dobles / Introducción ¿Distintos tipos de tests doubles? Hay una fina línea que los diferencia que depende del autor. • Dummy Objetos que son pasados como relleno de dependencias. Nunca son usados. • Fake Objetos que tienen una implementación funcional pero con atajos que les impiden ser viables para usarse en entornos de producción (una base de datos en memoria, por ejemplo). • Stubs Objetos que se preparan para ofrecer respuestas concretas a peticiones concretas. Pueden usar verificación de estado (Assert). • Mocks Objetos sobre los que se tiene algún tipo de expectativa. Tienen Asserts que verifican comportamiento.
  • 27. Dobles / Ejemplo 01 public class CustomerService 02 { 03 private ICustomerRepository _customerRepository; 04 private IComplaintRepository _complaintRepository; 05 private ICustomerCareNotificationService _customercareNotificationService; 06 07 public CustomerService(ICustomerRepository customerRepository, 08 IComplaintRepository complaintRepository, 09 ICustomerCareNotificationService customerCareNotificationService) 10 { 11 this._customerRepository = customerRepository; 12 this._complaintRepository = complaintRepository; 13 this._customercareNotificationService = customerCareNotificationService; 14 } 15 16 public List<string> Complaints(int clientId) 17 { 18 var complaints = _complaintRepository.GetAllFromClientId(clientId); 19 20 bool isAVipCustomer = _customerRepository.GetCustomerCategory(clientId); 21 if (isAVipCustomer) 22 SendNotificationToCustomerCare(clientId); 23 24 var result = complaints.Select(c => c.Title); 25 26 return result.ToList(); 27 } 28 29 private void SendNotificationToCustomerCare(int clientId) 30 { 31 this._customercareNotificationService.SendNotificationAboutVipCustomerComplaint(clientId); 32 } 33 }
  • 28. Hagamos los tests de ejemplo con Dobles
  • 30. SOLID / Introducción Serie de principios de desarrollo en programación orientada a objetos Originalmente recopilados por Robert C. Martín en 1995 Proporcionan un camino para conseguir código bajamente acoplado, altamente cohesivo que encapsule las necesidades de negocio correctamente
  • 31. SOLID / Introducción No es un framework No es una librería No son unos patrones No son un objetivo Son unos principios de diseño orientado a objetos Son un medio para conseguir código desacoplado Y por tanto un modo de hacer código más mantenible
  • 33. SOLID
  • 34. SOLID / Single Responsibility Principle (SRP) “Una clase debería tener una, y solo una, razón para cambiar ” Una clase debería tener una única responsabilidad. Podemos aplicarlo también a los métodos de la clase. Beneficios Proporciona un código más desacoplado y más fácil de mantener. Proporciona unas clases más pequeñas y limpias.
  • 35. SOLID / Single Responsibility Principle (SRP) 1 public class Reception 2 { 3 private string _receptionistName = "Peter"; 4 public string GetGreeting() 5 { 6 return string.Format("You are Welcome, my name is {0}", _receptionistName); 7 } 8 9 public string GetRoomKeys() 10 { 11 return "room 101"; 12 } 13 14 public string PrintInvoce(string roomKeys) 15 { 16 return string.Format("Your invoice for {0}", roomKeys); 17 } 18 }
  • 36. SOLID / Single Responsibility Principle (SRP) 1 public class Reception 2 { 3 private string _receptionistName = "Peter"; 4 public string GetGreeting() 5 { 6 return string.Format("You are Welcome, my name is {0}", _receptionistName); 7 } 8 9 public string GetRoomKeys() 10 { 11 return "room 101"; 12 } 13 14 public string PrintInvoce(string roomKeys) 15 { 16 return string.Format("Your invoice for {0}", roomKeys); 17 } 18 }
  • 38. SOLID / Single Responsibility Principle (SRP) 1 public class Reception 2 { 3 private string _receptionistName = "Peter"; 4 private RoomService _roomService = new RoomService(); 5 private InvoicePrinter _invoicePrinter = new InvoicePrinter(); 6 public string GetGreeting() 7 { 8 return string.Format("You are Welcome, my name is {0}", _receptionistName); 9 } 10 11 public string GetRoomKeys() 12 { 13 return _roomService.GetFreeRoom(); 14 } 15 16 public string PrintInvoce(string roomKeys) 17 { 18 return _invoicePrinter.Print(roomKeys); 19 } 20 }
  • 39. SOLID / Open-Closed Principle (OCP) “Una clase debería estar abierta a extensión pero cerrada a modificación” Deberíamos poder cambiar o extender el comportamiento de una clase, sin modificarla en absoluto. Beneficios Podemos añadir nueva funcionalidad sin dañar el código existente
  • 40. SOLID / Open-Closed Principle (OCP) 1 public class Reception 2 { 3 private string _receptionistName = "Peter"; 4 private RoomService _roomService = new RoomService(); 5 private InvoicePrinter _invoicePrinter = new InvoicePrinter(); 6 7 public string GetGreeting() 8 { 9 return string.Format("You are Welcome, my name is {0}", _receptionistName); 10 } 11 12 public string GetRoomKeys() 13 { 14 return _roomService.GetFreeRoom(); 15 } 16 17 public string PrintInvoce(string roomKeys) 18 { 19 return _invoicePrinter.Print(roomKeys); 20 } 21 } 1 public class InvoicePrinter 2 { 3 public string Print(string roomKeys) 4 { 5 return string.Format("Your invoice for room {0}", roomKeys); 6 } 7 }
  • 42. SOLID / Open-Closed Principle (OCP) 1 public class Reception 2 { 3 private string _receptionistName = "Peter"; 4 private RoomService _roomService = new RoomService(); 5 private InvoicePrinter _invoicePrinter = new InvoiceTextPrinter(); 6 7 public string GetGreeting() 8 { 9 return string.Format("You are Welcome, my name is {0}", _receptionistName); 10 } 11 12 public string GetRoomKeys() 13 { 14 return _roomService.GetFreeRoom(); 15 } 16 17 public string PrintInvoce(string roomKeys) 18 { 19 return _invoicePrinter.Print(roomKeys); 20 } 21 } 1 public abstract class InvoicePrinter 2 { 3 public abstract string Print(string roomKeys); 4 }
  • 43. SOLID / Open-Closed Principle (OCP) 1 public class Reception 2 { 3 private string _receptionistName = "Peter"; 4 private RoomService _roomService = new RoomService(); 5 private InvoicePrinter _invoicePrinter = new InvoiceHtmlPrinter(); 6 7 public string GetGreeting() 8 { 9 return string.Format("You are Welcome, my name is {0}", _receptionistName); 10 } 11 12 public string GetRoomKeys() 13 { 14 return _roomService.GetFreeRoom(); 15 } 16 17 public string PrintInvoce(string roomKeys) 18 { 19 return _invoicePrinter.Print(roomKeys); 20 } 21 } 1 public abstract class InvoicePrinter 2 { 3 public abstract string Print(string roomKeys); 4 }
  • 44. SOLID / Liskov Substitution Principle (LSP) “Sustituir un objeto por una subclase de ese objeto no debería cambiar el comportamiento o el buen funcionamiento del programa (o de su clase base)” Si una función recibe un objeto como parámetro, de tipo X y en su lugar le pasamos otro de tipo Y, que hereda de X, dicha función debe proceder correctamente. Una función que no cumple LSP, habitualmente rompe OCP, pues necesita saber demasiado de la clase ancestro para poder modificar su funcionamiento.
  • 45. SOLID / Liskov Substitution Principle (LSP) 1 static void Main(string[] args) 2 { 3 // Management 4 InvoiceCalculator invoiceCalculator = new InvoiceCalculator(); 5 invoiceCalculator.Base = 1000m; 6 invoiceCalculator.IVA = 0.21m; 7 8 var printerForReception = new InvoiceTextPrinter(); 9 var reception = new Reception(); 10 11 // Customer 12 Console.WriteLine(reception.GetGreeting()); 13 var roomKeys = reception.GetRoomKeys(); 14 15 Console.WriteLine(printerForReception.Print(roomKeys, invoiceCalculator)); 16 17 Console.ReadKey(); 18 }
  • 46. SOLID / Liskov Substitution Principle (LSP) 1 static void Main(string[] args) 2 { 3 // Management 4 InvoiceCalculator invoiceCalculator = new InvoiceForeignCalculator(); 5 invoiceCalculator.Base = 1000m; 6 invoiceCalculator.IVA = 0.21m; 7 8 var printerForReception = new InvoiceTextPrinter(); 9 var reception = new Reception(); 10 11 // Customer 12 Console.WriteLine(reception.GetGreeting()); 13 var roomKeys = reception.GetRoomKeys(); 14 15 Console.WriteLine(printerForReception.Print(roomKeys, invoiceCalculator)); 16 17 Console.ReadKey(); 18 }
  • 47. SOLID / Liskov Substitution Principle (LSP) Cuando un grupo de clases incumple LSP, es muy habitual que el problema subyacente resida en el diseño y que la única solución sea un rediseño completo de la jerarquía de clases.
  • 49. SOLID / Liskov Substitution Principle (LSP) 1 class Program 2 { 3 static void Main(string[] args) 4 { 5 // Management 6 InvoiceCalculator invoiceCalculator = new InvoiceLocalCalculator(1000m, 0.21m); 7 InvoiceCalculator invoiceCalculator = new InvoiceForeignCalculator(1000m); 8 9 var printerForReception = new InvoiceTextPrinter(); 10 var reception = new Reception(); 11 12 // Customer 13 Console.WriteLine(reception.GetGreeting()); 14 var roomKeys = reception.GetRoomKeys(); 15 16 Console.WriteLine(printerForReception.Print(roomKeys, invoiceCalculator)); 17 18 Console.ReadKey(); 19 } 20 }
  • 50. SOLID / Interface Segregation Principle (ISP) “Una clase cliente no debe ser forzada a depender de un interface que no necesita” Si una clase cliente usa un interface con más métodos de los que ella misma necesita es muy probable que ese interface sirva a varias clases cliente con responsabilidades diferentes. ISP y SRP están muy ligados. Un buen SRP habitualmente implica un buen ISP.
  • 51. SOLID / Interface Segregation Principle (ISP) 1 public class Receptionist : IStaff 2 { 3 private string _name; 4 public Receptionist(string name) 5 { 6 this._name = name; 7 } 8 9 public string GetName() 10 { 11 return _name; 12 } 13 public string GetDrink(string drinkName) 14 { 15 throw new NotImplementedException(); 16 } 17 public bool CheckReservation(string clientName) 18 { 19 return true; 20 } 21 } 1 public class Reception 2 { 3 ... 6 11 public string GetDrink() 12 { 13 return _receptionist.GetDrink("gin tonic"); 14 }
  • 53. SOLID / Interface Segregation Principle (ISP)
  • 54. SOLID / Dependency Inversion Principle (DIP) “Módulos de alto nivel no deberían depender de módulos de bajo nivel. Ambos deberían depender de abstracciones” “Abstracciones no deberían depender de los detalles. Los detalles deberían depender de las abstracciones” Una clase padre, accederá a sus dependencias a través de interfaces o clases abstractas. Diseñaremos nuestro sistema de arriba hacia abajo, no al revés.
  • 55. SOLID / Dependency Inversion Principle (DIP)
  • 57. SOLID / Dependency Inversion Principle (DIP) Cumplimos el primer punto del Principio de Inversión de Dependencia
  • 58. SOLID / Dependency Inversion Principle (DIP) Cumplimos los dos puntos del Principio
  • 59. Test Driven Development Introducción
  • 60. TDD / Introducción TODO CODIGO FALLA HASTA QUE SE DEMUESTRE LO CONTRARIO
  • 61. 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.
  • 62. TDD / Introducción ¿Qué ocurre cuando el nivel de estrés se eleva? Circulo de retroalimentación: “Kent Beck: Test Driven Development by Example”
  • 63. TDD ¿Qué es? ¿Cómo se hace? ¿Cómo me beneficia?
  • 64. 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
  • 65. TDD / Pasos ¿Qué queremos que haga el código que vamos a desarrollar? ¿Qué hechos demostrarán que nuestro código funciona?
  • 66. 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
  • 67. TDD / Pasos Escribimos el código de producción SOLO el código necesario para pasar el test
  • 68. TDD / Pasos Refactorizamos la funcionalidad desarrollada Durante la refactorización NO DEBEMOS cambiar la semántica (sentido)
  • 69. 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.
  • 70. TDD Patrones de Test Driven Development
  • 71. TDD / Patrones para un buen TDD / Tests 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
  • 72. TDD / Patrones para un buen TDD / Tests 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
  • 73. TDD / Patrones para un buen TDD / Assert First • Escribe tu Assert lo primero de todo 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. 01 [TestClass] 02 public void CarTravelDistanceTest() 03 { 04 Assert.IsTrue(car.IsPowerOff()); 05 Assert.Equals(300, distance.FromStart()); 06 }
  • 74. TDD / Patrones para un buen TDD / Assert First • Escribe tu Assert lo primero de todo • crece según sea necesario para alcanzar el objetivo ¿De donde sale la distancia? Del cuenta kilómetros del propio vehículo, desde luego 01 [TestClass] 02 public void CarTravelDistanceTest() 03 { 04 Distance distance = car.DistanceFromStart(); 05 Assert.IsTrue(car.IsPowerOff()); 06 Assert.Equals(300, distance.Kilometers()); 07 }
  • 75. TDD / 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 01 [TestClass] debemos conducirlo a donde queremos ir 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 }
  • 76. TDD / 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. • Sobre todo si la precisión de coma flotante puede ser un problema.
  • 77. TDD / 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());
  • 78. TDD Patrones de barra roja (Red Bar Patterns)
  • 79. 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 var allAccounts = new IDictionary<Company, IList<Accounts>>(); Assert.AreEqual( 0, allCounts.SumAllAccounts()); • a menudo un Starter Test es un test de alto nivel, como un test de aplicación
  • 80. TDD / 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.
  • 81. TDD / 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”
  • 82. TDD / 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
  • 83. TDD Patrones de barra verde (Green Bar Patterns)
  • 84. 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) 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? Porque es vital obtener un verde rápidamente y es mejor tener algo funcionando que no tener nada o algo que falla.
  • 85. TDD / 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 podemos denominar como el bucle de triangulación. [TestMeethod] public void TestSum() { Assert.Equals(4, Sum(3, 1)); } private int Sum(int x, int y) { return 4 } [TestMeethod] 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; } [TestMeethod] 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; }
  • 86. TDD / 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 ”.
  • 87. TDD / 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 [TestClass] 02 public void SumTest() 03 { 04 Assert.AreEqual(5, Calculations.Sum(5)); 05 } 01 public static int Sum(int number) 02 { 03 return number; 04 }
  • 88. TDD / 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 [TestClass] 02 public void SumTest() 03 { 04 Assert.AreEqual(5, Calculations.Sum(5, new int[] { 5 })); 05 } 01 public static int Sum(int number, int[] values) 02 { 03 return number; 04 }
  • 89. TDD / 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 [TestClass] 02 public void SumTest() 03 { 04 Assert.AreEqual(5, Calculations.Sum(5, new int[] { 5 })); 05 } 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 }
  • 90. TDD / 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 [TestClass] 07 public void SumTest() 08 { 09 Assert.AreEqual(5, Calculations.Sum(new int[] { 3, 2 })); 10 } 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 }
  • 91. SEATTLE www.plainconcepts.com MADRID General Rodrigo 6 Cuerpo alto, 1ª planta 28003 (+34) 915 346 836 BILBAO Nervión 3 6ª planta 48001 (+34) 946 008 168 1511 Third Avenue Suite 512 WA 98101 (+1) 206 708 1285 SEVILLA Avd. Innovación 3 Hércules, 3º planta, modulo 4 41020 (+34) 955 222 906

Notas del editor

  1. Pequeña demo de Unit Test con MSTests y/o Nunit (dependiendo del interés de la clase) con una Class que sume números (por ejemplo).
  2. Estos patrones que describen TIPOS de tests: son sobre CUANDO y DONDE escribes tus tests y también CUANDO PARAR de escribir tests.
  3. Un test rojo debe considerarse como una situación de alarma de nivel 1. Necesitas centrar toda tu atención en solucionarlo. Usa estos patrones para conseguir el resultado verde más rápido que sea posible incluso si ese resultado no es algo con lo que quieras convivir ni una hora
  4. Fake it viola YAGNI? Según Kent Beck, no porque la refactorización posterior eliminará el código YAGNI.
  5. Entendiendo por abstracción, la sustitución de constantes de retorno (return 5) por variables y/u operaciones: public void testSum() { assertEquals(4, plus(3, 1)); // assertEquals(7, plus(3,4)); }