02/07/2014
1
DCIC - UNSLic. Ariel Trellini
Clase 11
Desarrollo de Aplicaciones Empresariales • 277 Lic. Ariel Trellini • DCIC • UNS
Tests de Integración vs Tests Unitarios
Se tienen muchos puntos de fallaen un test de integración. Todas lasunidades tienen que trabajarjuntas y cualquiera de ellas podríafallar, haciendo muy difícil saber el origen de un bug.
Son más lentos de ejecutar
Son más propensos a dejar efectoscolaterales
Pueden ser más sencillos de codificar, aunque más frágiles.
Unit Testing
Un test de integración ejercita
muchas unidades de código
que trabajan juntas para
evaluar uno o más resultados
esperados del software.
Desarrollo de Aplicaciones Empresariales • 278 Lic. Ariel Trellini • DCIC • UNS
Frameworks de Tests Unitarios
Son para los tests unitarios como las IDE para el desarrollo.
Facilitan 3 aspectos del ciclo de vida de unit testing: La escritura de tests
La ejecución de tests
La revisión de resultados
Unit Testing
Usar un framework de tests unitarios no asegura que los test
que escribimos sean legibles, mantenibles, dignos de
confianza, o que cubren toda la lógica que queremos testear.
Desarrollo de Aplicaciones Empresariales • 279 Lic. Ariel Trellini • DCIC • UNS
¿Cómo ayudan a los desarrolladores a escribir y ejecutar tests y a revisar los resultados?
Unit Testing Frameworks de Tests Unitarios
Práctica de Unit Testing Cómo ayuda el framework
Escribir tests fácilmente y de manera estructurada
Los frameworks proveen una librería de clases que contiene:• Clases base o interfaces para hererdar• Atributos para poner en tu código para marcar los tests a
ejecutar.• Clases de aserción que tiene métodos a invocar que permiten
verificar los resultados.
Ejecutar uno o todos los tests unitarios
Los frameworks proveen un test runner (consola o GUI) que:• Identifica los tests en tu código• Ejecuta los tests automáticamente• Indica el estado mientras está ejecutando• Puede automatizarse por línea de comandos
Revisar los resultados de lasejecuciones
Los test runners proveen información como:• Cuántos tests se ejecutaron, cuántos no se ejecutaron y cuántos
fallaron• Qué tests fallaron y la razón por la cual falló cada uno• Los mensajes de los asserts que fallaron.• El código que falló y posiblemente el stack trace de cualquier
excepción que haya ocasionado la falla.
Desarrollo de Aplicaciones Empresariales • 280 Lic. Ariel Trellini • DCIC • UNS
Características Comunes Todos los frameworks de la familia xUnit implementan un conjunto básico
de características, que permiten realizar las siguientes tareas
Especificar un test como un Test Method
Especificar los resultados esperados dentro del test method en forma de llamadas a Assertion Methods
Componer los tests en Test Suites que pueden ser corridas en una únicaoperación.
Ejecutar uno o más tests y obtener un reporte de los resultados
Frameworks Existentes .Net: NUnit, MSTest, NUnitASP, xUnit.net
Java: JUnit, Cactus
Javascript: JSUnit, JSTest, RhinoUnit, JSSpec, TestSwarm, JsTestDriver.
PHP: PHPUnit, SimpleTest
Unit Testing Frameworks de Tests Unitarios
Desarrollo de Aplicaciones Empresariales • 281 Lic. Ariel Trellini • DCIC • UNS
Organizando los Tests Mecanismos Básicos de xUnit
El código de test se pone en un Test Method
Los test methods se agrupan en Test Classes
A su vez, las test classes se agrupan en Test Suites que contienen todos los test methods de las test classes involucradas.
El Test Runner se encarga de ejecutar Test Suites o tests
Unit Testing
Estructura de tests estática
02/07/2014
2
Desarrollo de Aplicaciones Empresariales • 282 Lic. Ariel Trellini • DCIC • UNS
¿Qué Incluiríamos en un Test Method? Principalmente, las 4 fases clásicas:
Fixture Setup, Ejercitar el SUT, Verificación de Resultados, Fixture Teardown.
No todas las fases necesitan estar en el Test Method
Preferentemente, una única condición de test por Test Method:
Ejecuta un único path de código y ejecuta siempre el mismo en cada corrida. Esto facilita que el test sea repetible.
Tenderíamos a tener un test method por cada camino posible, logrando unacobertura de código total.
Permite localizar fácilmente el defecto
Minimiza el solapamiento de tests, ya que tendremos pocos tests a modificar simodificamos el SUT.
Unit Testing Organizando los Tests
Desarrollo de Aplicaciones Empresariales • 283 Lic. Ariel Trellini • DCIC • UNS
Test Methods y Testcase Classes Testcase Class per Class
Una única Testcase Class mantiene todos los Test Methods para todo el comportamiento de la clase SUT.
Generalmente tendremos una correspondencia 1 a 1 entre una clase (SUT) y suclase de prueba (Testcase Class).
Generalmente usado cuando cada tests necesita un fixture ligeramentediferente. Conviente factorizar la creación del fixture para reutilización.
Unit Testing Organizando los Tests
Desarrollo de Aplicaciones Empresariales • 284 Lic. Ariel Trellini • DCIC • UNS
Testcase Class per Feature
Agrupar todos los Test Methods que verifican una característica particular del SUT en una sola Testcase Class.
Feature: Uno o más métodos y atributos que colectivamente implementan alguna funcionalidad del SUT.
Es apropiado cuando escribimos test contra un Service Façade, ya que permitemantener juntos todos los tests sobre una feature del Service Façade.
Facilita la visión de las condiciones de test para esa característica.
Código de inicialización del Fixture repetido en diferentes clases de test.
Unit Testing Organizando los Tests Test Methods y Testcase Classes
Desarrollo de Aplicaciones Empresariales • 285 Lic. Ariel Trellini • DCIC • UNS
Testcase Class per Fixture
Agrupar en una Testcase Class todos los Test Methods que utilicen el mismo Fixture (mismas pre-condiciones).
Es comunmente usado cuando escribimos tests unitarios para objetos con estado y cada método necesita ser testeado en cada estado del objeto
Facilita poner el código de setup del Fixture en el método de inicialización de la Testcase Class.
Las pruebas sobre las características del SUT estarán probablemente distribuidas en diferentes clases de test
Unit Testing Organizando los Tests Test Methods y Testcase Classes
Desarrollo de Aplicaciones Empresariales • 286 Lic. Ariel Trellini • DCIC • UNS
Convenciones de Nombres de Tests Los nombres de los paquetes, clases y métodos de tests deberían cubrir al
menos lo siguiente:
El nombre de la clase del SUT.
El nombre del método o característica siendo probado.
Características importantes de valores de entrada para probar el SUT.
Cualquier cosa relevante sobre el estado del SUT o sus dependencias.
La respuesta esperada después de ejercitar el SUT. Esto podría incluirse en el Test Method, prefijado por un “should”o “debería”.
Con esto podríamos deducir exactamente qué condiciones de tests hemostesteado con sólo mirar los nombres de las clases y métodos en la IDE.
Ejemplo:
Unit Testing Organizando los Tests
Codificación Tests Unitarios
Proyecto ServiciosDominio ServiciosDominioTests
Clase ServicioEmpleados ServicioEmpleadosTest
Método ObtenerEmpleadoPorFiltro ObtenerEmpleadoPorFiltro_NombreEmpleado_VacioObtenerEmpleadoPorFiltro_NombreEmpleado_NoVacio
Desarrollo de Aplicaciones Empresariales • 287 Lic. Ariel Trellini • DCIC • UNS
Reutilización del Código de Test Consideraciones
Evitar la duplicación de código de test. Esto facilitará el mantenimiento de los tests.
Mantener el objetivo de pruebas como documentación:
Que no se factorice tanto el código de la prueba unitaria que resulte complicado entender que está probando o las características del SUT.
Técnicas para factorizar código
Setup implícito: Muchos frameworks de test ofrecen métodos que se ejecutan implícitamente antes y después de cada prueba. Se puede poner aquí código de inicialización y finalización común a todas las pruebas.
Métodos de ayuda: Métodos que implementan funcionalidad repetida en muchos tests. Algunos de estos métodos pueden ser:
Métodos de creación de entidades que serán entradas al SUT
Métodos de validación de resultados devueltos por el SUT
Estos métodos de ayuda se podrían ubicar:
Dentro de una clase padre de las clases de test
Como una clase aparte
Como métodos privados dentro de una clase de test
Unit Testing Organizando los Tests
02/07/2014
3
Desarrollo de Aplicaciones Empresariales • 288 Lic. Ariel Trellini • DCIC • UNS
Usando dobles de riesgo: Stubs y Mocks
Motivación Cuando una clase no depende de otra, el testeo de la clase es
relativamente directo
Cuando una clase sí depende de otra (DOC: depended-on component), tenemos dos alternativas:
Podemos testearlas en conjunto
Podemos aislarla para testearla por separado
Unit Testing
Desarrollo de Aplicaciones Empresariales • 289 Lic. Ariel Trellini • DCIC • UNS
Inputs Indirectos
¿Cómo controlamos los Inputs Indirectos?
Debemos ser capaces de controlar el DOC para que retorne cada tipo posible de valor de retorno.
Tipos de inputs indirectos:
Valores de retorno de métodos/funciones
Valores de argumentos actualizables
Excepciones que podrían dispararse
Unit Testing Usando dobles de riesgo: Stubs y Mocks
Los inputs indirectos son los
valores retornados por el
DOC durante la ejecución del
test unitario.
Desarrollo de Aplicaciones Empresariales • 290 Lic. Ariel Trellini • DCIC • UNS
Opciones de control
Back Door Setup: Cuando el SUT almacena su estado en otrocomponente, el test debe podermanipular ese estado interactuandodirectamente con aquelcomponente.Sin embargo, en muchos casos estaalternativa no es práctica o no es posible.
Test Stub: Una forma de controlarel DOC es reemplazarlo por un stub. Antes de ejercitar el SUT, configuramos al stub para queretorne los valores deseadosal momento que el SUT lo ejecute.
Unit Testing Usando dobles de riesgo: Stubs y Mocks Inputs Indirectos
Desarrollo de Aplicaciones Empresariales • 291 Lic. Ariel Trellini • DCIC • UNS
Outputs Indirectos
¿Cómo verificamos los Outputs Indirectos?
Debemos ser capaces de observarlas llamadas que el SUT hace a la API del DOC.
Unit Testing Usando dobles de riesgo: Stubs y Mocks
Los outputs indirectos son
aquellos resultados o efectos
colaterales de la ejecución
del método testeado que no
se retornan como datos de
salida.
Desarrollo de Aplicaciones Empresariales • 292 Lic. Ariel Trellini • DCIC • UNS
Opciones de verificación
Back Door Verification: El test usaal DOC como un punto de observación para determinar cómoes usado dicho DOC por el SUT.Sin embargo, en muchos casos estaalternativa no es práctica o no esposible.
Procedural Behavior Verification: Captura las llamadas a un DOC durante la ejecución del SUT y luegolas compara con las llamadasesperadas cuando el SUT ha terminado su ejecución.
Reemplazar el DOC por un Test Spy que registre todas las llamadas querecibe y luego utilice métodos de aserción para compararlas con lasllamadas esperadas.
Unit Testing Usando dobles de riesgo: Stubs y Mocks Outputs Indirectos
Desarrollo de Aplicaciones Empresariales • 293 Lic. Ariel Trellini • DCIC • UNS
Opciones de verificación
Expected Behavior Verification: Construir una “especificación de comportamiento” durante el fixture del test y comparar el comportamiento real con el esperado.
Reemplazar el DOC por un Mock Object, configurar al Mock Object con las llamadasesperadas, comparar las llamadas recibidas con las esperadas y fallar inmediatamentesi se recibe una llamada inesperada.
Unit Testing Usando dobles de riesgo: Stubs y Mocks Outputs Indirectos
02/07/2014
4
Desarrollo de Aplicaciones Empresariales • 294 Lic. Ariel Trellini • DCIC • UNS
Tipos de Dobles de Tests Objeto Dummy
Es un objeto que existe solamente para ser pasado al SUT como argumento (o un atributo de un argumento), pero nunca es realmente usado.
Test Stub
Es un objeto que actúa como punto de control para despachar inputs indirectosal SUT cuando los métodos del Test Stub son invocados.
Tipos
Responder: Inyecta inputs indirectos al SUT vía retornos de métodos.
Saboteur: Lanza excepciones o errores para inyectar al SUT inputs indirectosanormales.
Unit Testing Usando dobles de riesgo: Stubs y Mocks
Un Doble de Test (Test Double) es un objeto o componente
que instalamos en lugar de componente real, con el
propósito expreso de ejecutar un test.
Desarrollo de Aplicaciones Empresariales • 295 Lic. Ariel Trellini • DCIC • UNS
Test Spy
Es un Test Stub con la capacidad de registrar todas las llamadas hechas a susmétodos. Luego realiza una serie de aserciones para comparar las llamadasrecibidas por el test spy con las esperadas [Outputs indirectos].
Mock Object
Compara las llamadas reales recibidas con las previamentes definidas comoesperadas a través de aserciones, haciendo fallar el test en caso de una llamadainesperada [Outputs indirectos].
Existen dos tipos:
Mock Object Estricto: Falla el test si las llamadas correctas son recibidas en un ordendiferente al esperado.
Mock Object Permisivo: Tolera llamadas fuera de orden. Falla el test si las llamadascorrectas son recibidas en un orden diferente al esperado.
Fake Object
Difiere en que no es directamente controlado u observado por el test.
Implementa la misma funcionalidad (o un subconjunto) que el DOC real.
Generalmente se utiliza cuando el DOC aun no existe, es demasiado lento o no está disponible en el ambiente de test.
Unit Testing Usando dobles de riesgo: Stubs y Mocks Tipos de Dobles de Tests
Desarrollo de Aplicaciones Empresariales • 296 Lic. Ariel Trellini • DCIC • UNS
Roadmap para realizar tests unitarios efectivosAlgunos necesidades de pruebas son más importantes que otras. Por esto, es necesario priorizar las pruebas a realizar para mejorar la completitud incrementalmente.
1. Ejercitar el “happy path”
Setear un estado simple requerido para ejercitar el SUT.
Ejercitar el SUT llamando al método a probar.
2. Verificar salidas directas del “happy path”
Llamar a métodos Assert sobre la salida del método.
Llamar a métodos Assert sobre el estado post-test.
3. Verificar caminos alternativos
Cambiar los valores de los parámetros con los que se llama al método del SUT.
Cambiar el estado previo al test del SUT.
Controlar entradas indirectas al SUT mediante test stubs.
4. Verificar comportamiento de la salida indirecta
Usar mock objects para interceptar y verificar llamadas a métodos que se realizan dentro del método del SUT que se prueba
Unit Testing
Desarrollo de Aplicaciones Empresariales • 297 Lic. Ariel Trellini • DCIC • UNS
Test Driven Development (TDD)
Forma tradicional de escribir Test Unitarios
Unit Testing
Escribirmétodo, claseo aplicación
Escribir tests unitario
(si hay tiempo)
Ejecutar tests unitarios
(si hay tiempo)
Corregirbugs
Desarrollo de Aplicaciones Empresariales • 298 Lic. Ariel Trellini • DCIC • UNS
Test Driven Development Process Overview
Unit Testing TDD
Escribir tests Ejecutar tests
Hacer que los tests pasenescribiendocódigo de
producción
Ejecutar tests
Si fallan, corregir bugs
Si pasan y no necesitan
refactoring, escribir un nuevo test.
Si pasan, refactorizar el
código de producción.
Desarrollo de Aplicaciones Empresariales • 299 Lic. Ariel Trellini • DCIC • UNS
La Técnica Escribir un test que falle para probar código o funcionalidad que aun no
tiene el producto final.
Hacer que los tests pasen escribiendo código de producción que cumplacon las expectativas de los tests.
Refactorizar el código generado
Unit Testing TDD