Tema 3. Test Driven Development



Documentos relacionados
Pruebas de unidad con JUnit

Las propiedades de la clase en java es el equivalente a las variables globales en lenguajes estructurados como el C.

En cualquier caso, tampoco es demasiado importante el significado de la "B", si es que lo tiene, lo interesante realmente es el algoritmo.

Modulo 1 El lenguaje Java

Solución al Examen de Prácticas de Programación (Ingeniería Informática)

UNIDAD 1. LOS NÚMEROS ENTEROS.

Refactorizar (v) Reestructurar el software aplicando una secuencia de refactorizaciones.

Demo. TDD desde Cero. Acceptance Test Driven Development.

Capitulo 3. Test Driven Development

El control de la tesorería consiste en gestionar desde la aplicación los cobros y pagos generados a partir de las facturas de venta y de compra.

Ejercicio 1 (3 puntos).-

GESTIÓN DE EXCEPCIONES EN JAVA. CAPTURA CON BLOQUES TRY CATCH Y FINALLY. EJEMPLOS RESUELTOS. (CU00927C)

Mantenimiento Limpieza

GESTINLIB GESTIÓN PARA LIBRERÍAS, PAPELERÍAS Y KIOSCOS DESCRIPCIÓN DEL MÓDULO DE KIOSCOS

Un elemento de cualquier clase llamada Info; Un puntero a un nuevo nodo llamado sig; De tal forma una unión de nodos hace que tengamos una lista:

Examen Junio- Grupo A Lunes 17 de Junio - Programación en C++ Pág. 1

INTELIGENCIA EN REDES DE COMUNICACIONES PRÁCTICA FINAL. Ignacio Ribas Ramos Miguel Flecha Lozano Ingeniería de Telecomunicaciones

Tutorial de FrontPage

La nueva criba de Eratóstenes Efraín Soto Apolinar 1 F.I.M.E. U.A.N.L. San Nicolás, N.L. México. efrain@yalma.fime.uanl.mx

Divisibilidad y números primos

Examen Septiembre Curso Programación en C++ Pág. 1

MANUAL SERVICIOS TELEFONIA FIJA

Ejercicios - Persistencia en Android: ficheros y SQLite

Formas de Pago y Efectos en Facturas de Venta WhitePaper Febrero de 2007

Copia de Seguridad en windows

Ciclo de vida y Metodologías para el desarrollo de SW Definición de la metodología

1. Ejemplo de clase : La clase Cuenta 2. Uso de la clase Cuenta. 3. Métodos y objetos receptores de mensajes (Importante)

Objetivos de la práctica: - Practicar uso de ficheros: abrir, cerrar y tratamiento de información contenida en el fichero.

Cualquier lenguaje de contexto libre, L, puede ser generado por medio de una GCL, G, que cumpla las siguientes condiciones:

MANUAL DE AYUDA MODULO TALLAS Y COLORES

Unidad I. 1.1 Sistemas numéricos (Binario, Octal, Decimal, Hexadecimal)

Introducción al Proceso de Pruebas.

MANUAL PARA LA GESTIÓN DEL PRÉSTAMO ENTRE LAS BIBLIOTECAS DE LA RED DE LECTURA PÚBLICA DE EUSKADI

Acciones pueden haber en Flash más de 1000 por lo tanto no se trata de aprenderlas de memoria sino de utilizarlas cuando nos interese.

Práctica del paso de generación de Leads

Introducción a la Programación en MATLAB

COMO CONFIGURAR UNA MAQUINA VIRTUAL EN VIRTUALBOX PARA ELASTIX

Programación Orientada a Objetos. Java: Excepciones

CONSULTAS CON SQL. 3. Hacer clic sobre el botón Nuevo de la ventana de la base de datos. Aparecerá el siguiente cuadro de diálogo.

Concesionario de coches

APROVECHAR LA BASE DE DATOS BIBLIOGRÁFICOS REBECA CON EL PRO- GRAMA ABIES.

PROCEDIMIENTOS DE TÍTULOS. Para solicitar los títulos al finalizar determinadas enseñanzas es preciso seguir un proceso en la aplicación Plumier XXI.

RESUMEN DE CONCEPTOS BASICOS DE PROGRAMACION JAVA

MICROSOFT WORD 2007 AVANZADO. Unidad Didáctica Nº 1

Gestión de Subtotales en Documentos de Venta WhitePaper Febrero de 2007

Creando una webquests

Euclides extendido y Test de primalidad probabiĺıstico

LAS SUBCONSULTAS SQL SERVER Manual de Referencia para usuarios. Salomón Ccance CCANCE WEBSITE

Guía de integración del módulo Paga+Tarde en Prestashop

GUÍA DE USO DE LA PLATAFORMA DE FORMACIÓN

Solución a las diferentes preguntas que puedan entrar en el examen de CCNA. David Santos Aparicio

OPERACIONES EN MOSTRADOR

Uso del Programa Gantt Project

Capítulo 9. Archivos de sintaxis

Hot Potatoes, aplicaciones educativas

Guía Rápida Preguntas Frecuentes

PRACTICA DE REDES Redes Ad Hoc

USO ADECUADO PARA ENVIAR CORREOS CON ARCHIVO ADJUNTO

MANUAL DE AYUDA HERRAMIENTA DE APROVISIONAMIENTO

BETA. Sacándole Partido a JUnit. Mocking. formacion@iwt2.org

Adaptación al NPGC. Introducción. NPGC.doc. Qué cambios hay en el NPGC? Telf.: Fax.:

Versión Página 2 de 29

Departamento CERES Área de Tarjetas Inteligentes Manual de Usuario

ETS Caminos Santander. Curso Ejercicios de introducción a la programación.

Primer Parcial Septiembre 5 de 2009

Tema 3: Herencia en C++ Programación Orientada a Objetos Curso 2008/2009 Begoña Moros Valle

En términos generales, un foro es un espacio de debate donde pueden expresarse ideas o comentarios sobre uno o varios temas.

CÓMO CREAR NUESTRO CATÁLOGO

Manual de usuario investigador

PANEL DE CONTROL (Zona de Administración) MANUAL DE USO Por conexanet. Revisión 1.1 Fecha

RESOLUCIÓN DE INCIDENCIAS PROCURADORES

La elección de Blogger como la plataforma o lugar donde

Este programa mueve cada motor de forma independiente, y cuando termina una línea pasa a la siguiente.

Actualmente existen dos maneras de enviar y publicar las estadísticas en la página web de la Federación Española de Baloncesto:

Ministerio de Educación. Diseño de Presentaciones en la Enseñanza. Módulo 9: Imprimir

Prof. Dr. Paul Bustamante

Programación Orientada a Objetos. Java: Excepciones

Creación paso a paso de Formularios con Google (Parte I) (AKA: no corrijo nunca más!)

Guía de Registro de Proveedores

Volumen TECNOLOGÍA DE ADMINISTRACIÓN EMPRESARIAL SIMI EVOLUTION (9.0) Guía de usuario

Guía de uso del sistema CV-Online

Introducción a la Estadística con Excel

Este es un ejemplo muy sencillo, un esquema de empleados que trabajan en proyectos, en una relación muchos a muchos.

Tutorial: Instalación de Eclipse para programar Android en Windows

Múltiplos y divisores

Práctica 5. Curso

Técnicas Avanzadas de Testing Automatizado

GUÍA DE GRABACIÓN Y EDICIÓN EN AUDACITY

Uso de excepciones en Java

Cómo convertir texto de Word en una tabla de datos en Excel (todas las versiones)

Creación de un Programa Ladder en el Simatic Manager

Módulo de Limpieza Anexo Manual Gran Hotel

INSTALACIÓN Y REGISTRO

Instalar protocolo, cliente o servicio nuevo. Seleccionar ubicación de red. Práctica - Compartir y conectar una carpeta

Control de objetivos y alertas mediante Tablas Dinámicas

Internet como herramientas de comunicación: El correo electrónico

Práctica 1 - Pista de Carreras Programación II

A25. Informática aplicada a la gestión Curso 2005/2006 Word Tema 3. Formato de sección.

Selección de los puntos de montaje

Transcripción:

Tema 3. Test Driven Development Ejercicios Resueltos Ejercicio 01. Desarrolle mediante TDD una implementación del algoritmo de la Criba de Eratóstenes para calcular la lista de los números primos desde 2 hasta un número n indicado. Si no existiera ningún primo, el algoritmo devolverá una lista vacía. El algoritmo de la criba de Eratóstenes se muestra a continuación. 1. Se crea una lista con los números desde 2 hasta n. 2. Se elige el siguiente número x no marcado (inicialmente el 2). 3. Se marcan todos los múltiplos de dicho número (x*2, x*3, etc.). 4. Se repite desde el paso 2. Cuando se ha terminado con todos los números aquellos que queden sin marcar son primos. Más información sobre la criba de Eratóstenes en la Wikipedia: http://en.wikipedia.org/wiki/sieve_of_eratosthenes Solución Antes de comenzar con la implementación es interesante pararse un momento a estudiar los posibles casos de prueba de este algoritmo. El único valor de entrada de las pruebas es el número n límite para calcular los números primos. Los casos de prueba se pueden dividir en varias particiones equivalentes en función de dicho n. Vamos a describir estas particiones a continuación. La primera partición engloba a todos los números menores de 2. Para cualquier valor de dicha partición el resultado de esta implementación será siempre el mismo: una lista vacía de números. Después, podemos definir tantas particiones como valores son necesarios para incluir a un nuevo número primo. También podemos jugar con particiones que terminan justo en un valor primo o justo después (por ejemplo, calcular todos los primos hasta 11 o hasta 12). Todos son equivalentes a la hora de generar ya que el proceso para calcularlo son los mismos, pero alguna prueba adicional puede ayudarnos a detectar errores ocultos. Veamos las primeras evoluciones aplicando TDD. public void testcalculaconvalorinicialuno() { List<Integer> l = CrivaDeEratosthenes.Calcula(1); asserttrue(l.isempty()); static class CrivaDeEratosthenes { 1

public static List<Integer> Calcula(int i) { return new ArrayList<Integer>(); //----------------------------------- public void testcalculaconvalorinicialdos() { List<Integer> l = CrivaDeEratosthenes.Calcula(2); // (*) assertequals(1, l.size()); assertequals(new Integer(2), l.get(0)); public static List<Integer> Calcula(int i) { List<Integer> l = new ArrayList<Integer>(); if (i >= 2) l.add(2); return l; (*) Aunque los dos asserts verifican lo mismo, con el primer assert evitamos que la prueba falle por una excepción si no hay ningún elemento en la lista. Hacer este cambio hace más legible la traza de la prueba cuando no hay ningún elemento en la lista. Al final de la traza veremos una manera más cómoda de escribir este tipo de asserts utilizando la librería de Java. Continuamos aplicando TDD. public void testcalculaconvalorinicialuno() { List<Integer> l = CrivaDeEratosthenes.Calcula(1); asserttrue(l.isempty()); public void testcalculaconvalorinicialdos() { List<Integer> l = CrivaDeEratosthenes.Calcula(2); assertequals(new Integer(2), l.get(0)); public void testcalculaconvalorinicialtres() { List<Integer> l = CrivaDeEratosthenes.Calcula(3); assertequals(2, l.size()); assertequals(new Integer(2), l.get(0)); assertequals(new Integer(3), l.get(1)); public static List<Integer> Calcula(int i) { List<Integer> l = new ArrayList<Integer>(); if (i >= 2) { l.add(2); l.add(3); return l; 2

En este nuevo paso vemos dos detalles interesantes. La primera es que ha sido necesario quitar el assert que pusimos para evitar un error por excepción. La segunda es que introducir una nueva prueba no ha hecho avanzar. Es necesario cambiar de enfoque. Llegados a este punto ya nos damos cuenta de que los casos de prueba no ayudan a evolucionar el código. Tendríamos que dar un paso muy grande con muchos cambios que pueden salir mal para implementar el código del algoritmo. Este es el momento de buscar alternativas para hacer pruebas más pequeñas y avanzar pasos más diminutos. Para ello cada paso del algoritmo será un método y cada uno de los métodos irá creciendo guiado por pruebas. Aunque dichos métodos deberían ser privados, los pondremos con el ámbito de visibilidad necesario para poder probarlos. En el próximo módulo veremos las técnicas y herramientas para poder probar métodos privados. Empezamos con una primera prueba que nos haga avanzar en este paso. El primer paso que vamos a abordar es crear una matriz de booleanos para indicar qué números están marcados y cuáles no. public void testcrealistadenumerossinmarcar() { int tope = 4; List<Boolean> l = CrivaDeEratosthenes.CreaListaDeNumerosSinMarcar(tope); assertequals((tope+1), l.size()); for (Boolean b:l) { assertfalse(b); public static List<Boolean> CreaListaDeNumerosSinMarcar(int i) { List<Boolean> lb = new ArrayList<Boolean>(); for (int c=0; c<=i; c++) lb.add(false); return lb; Necesitamos incrementar el tope en 1 ya que para que el número 4 aparezca en la lista de marcados, es necesario que la lista tenga 5 elementos (del 0 al 5). Como trabajamos con listas, ignoraremos las posiciones 0 y 1 que siempre serán false ya que no intervienen. Continuamos. public void testmarcarmultiplos() { int tope = 2; List<Boolean> l = CrivaDeEratosthenes.CreaListaDeNumerosSinMarcar(2); CrivaDeEratosthenes.MarcarMultiplos(l); assertfalse(l.get(2)); public static void MarcarMultiplos(List<Boolean> l) { Cuidado! Hemos descubierto un mal caso de prueba, el nombre es poco descriptivo y no le estamos pidiendo a nuestro sistema que haga nada por eso un método vacío lo pasa. Vamos a cambiar este caso de prueba. Vamos a utilizar como valor de prueba 4 porque es el primer valor que introduce un cambio. Continuamos. 3

public void testmarcarmultiploshasta4() { List<Boolean> l = CrivaDeEratosthenes.CreaListaDeNumerosSinMarcar(4); CrivaDeEratosthenes.MarcarMultiplos(l); assertfalse(l.get(2)); assertfalse(l.get(3)); asserttrue(l.get(4)); public static void MarcarMultiplos(List<Boolean> l) { for (int num = 2; num < l.size(); num++) { for (int mul = (num*2); mul < l.size(); mul += num) { l.set(mul, true); //----------------------------------- public void testcrearlistadeprimoshasta4() { List<Boolean> l = CrivaDeEratosthenes.CreaListaDeNumerosSinMarcar(4); CrivaDeEratosthenes.MarcarMultiplos(l); List<Integer> primos = CrivaDeEratosthenes.CreaListaDePrimos(l); assertequals(2, primos.size()); assertequals(new Integer(2), primos.get(0)); assertequals(new Integer(3), primos.get(1)); public static List<Integer> CreaListaDePrimos(List<Boolean> l) { List<Integer> lb = new ArrayList<Integer>(); for (int c = 2; c < l.size();c++) { if (!l.get(c)) { lb.add(c); return lb; Ya tenemos implementados y probados todos los pasos. Ahora es el momento de refactorizar el método que calcula la criba de Eratóstenes y comprobar que las primeras pruebas que escribimos siguen funcionando. Veamos la refactorización. public static List<Integer> Calcula(int i) { List<Boolean> lb = CreaListaDeNumerosSinMarcar(i); MarcarMultiplos(lb); return CreaListaDePrimos(lb); Las pruebas siguen funcionando por lo que ya podemos dar por terminada la implementación. Si embargo podemos añadir algunas pruebas más jugando con las particiones que comentamos al principio. Por ejemplo: 4

public void testgeneraprimoshastadoce() { List<Integer> l = CrivaDeEratosthenes.Calcula(12); Assert.assertEquals(l, Arrays.asList(2, 3, 5, 7, 11)); Consideraciones finales Este desarrollo ha tenido una carencia. No se ha podido hacer TDD para definir que el método principal llame a los demás métodos ni verifica si el orden en que los llama es el correcto, con lo que hemos diseñado esa parte sin el soporte de pruebas. Este tipo de TDD lo realizaremos mediante mocks los cuáles estudiaremos en el siguiente módulo. Ejercicio 02. Se desea crear una clase que funcione como un contador. Se cuenta con los siguientes requisitos. Al crear el contador indicamos el valor inicial del mismo, el incremento y el valor límite. El valor inicial y el incremento tomarán un valor de 0 y 1 respectivamente si no se indica nada. El límite es necesario indicarlo siempre. Ninguno de los tres valores (valor inicial, incremento y límite) pueden cambiarse una vez creado el contador Al incrementar el contador se suma al valor actual el incremento y nos indican si se superó el límite. Cuando se supere el límite, el valor actual del contador vuelve a ser el valor inicial. En cualquier momento se puede conocer el valor actual del contador y E cualquier momento se puede establecer el contador a su valor inicial. Implemente los requisitos anteriores utilizando TDD. Solución Esta solución muestra la línea temporal del trabajo hecho. Cada boque de código (entre dos comentarios con guiones) es la implementación de una característica en el código. Primero se muestra el código de prueba y, después, la implementación. También se indican las refactorizaciones realizadas. 5

Esta misma traza y el código Java obtenido pueden descargarse en la sección de materiales del curso. En el boletín de ejercicios de este tema se plantean cuestiones adicionales a partir de esta solución. public void testvervalordelcontadorpordefecto() { ContadorCircular cc = new ContadorCircular(); assertequals(0, cc.getvalor()); public class ContadorCircular { public int getvalor() { return 0; //----------------------------------------- public void testvervalordelcontadorconvalorinicial5() { ContadorCircular cc = new ContadorCircular(5); assertequals(5, cc.getvalor()); public class ContadorCircular { int valor; public ContadorCircular(int i) { this.valor = i; public ContadorCircular() { this(0); public int getvalor() { return this.valor; //----------------------------------------------- public void testincrementarcontadorpordefecto() { ContadorCircular cc = new ContadorCircular(); cc.incrementa(); assertequals(1, cc.getvalor()); public void incrementa() { this.valor++; //------------------------------------------------- 6

public void testincrementarcontadorde5a10() { ContadorCircular cc = new ContadorCircular(5, 5); cc.incrementa(); assertequals(10, cc.getvalor()); public class ContadorCircular { int valor; int incremento; public ContadorCircular(int i) { this.valor = i; this.incremento = 1; public ContadorCircular() { this(0); public ContadorCircular(int i, int j) { this(i); this.incremento = j; public int getvalor() { return this.valor; public void incrementa() { //------------------------------------------------- /* Refactorizamos - Nombres de parámetros de constructores más descriptivos - Quitamos un constructor. - Creamos los contadores en el setup - nombres más descriptivos para los contadores de pruebas */ public class TestContadorCircular { ContadorCircular ccpordefecto; ContadorCircular cccincoencinco; @Before public void setup() throws Exception { ccpordefecto = new ContadorCircular(); cccincoencinco = new ContadorCircular(5, 5); public void testvervalordelcontadorpordefecto() { assertequals(0, ccpordefecto.getvalor()); public void testvervalordelcontadorconvalorinicial5() { assertequals(5, cccincoencinco.getvalor()); 7

public void testincrementarcontadorpordefecto() { ccpordefecto.incrementa(); assertequals(1, ccpordefecto.getvalor()); public void testincrementarcontadorde5a10() { cccincoencinco.incrementa(); assertequals(10, cccincoencinco.getvalor()); public class ContadorCircular { int valor; int incremento; public ContadorCircular(int valor, int incremento) { this.valor =valor; this.incremento = incremento; public ContadorCircular() { this(0, 1); public int getvalor() { return this.valor; public void incrementa() { @Before public void setup() throws Exception { ccpordefecto = new ContadorCircular(1); cccincoencinco = new ContadorCircular(5, 5); public void testlimitenosuperadocontadorpordefecto() { boolean b = this.ccpordefecto.incrementa(); assertfalse(b); int limite; public ContadorCircular(int limite) { this(0, 1); this.limite = limite; public boolean incrementa() { return false; 8

public void testlimitesuperadocontadorpordefecto() { this.ccpordefecto.incrementa(); boolean b = this.ccpordefecto.incrementa(); asserttrue(b); public boolean incrementa() { return this.valor > this.limite; public void testlimitesuperadocontadorde5en5() { this.cccincoencinco.incrementa(); boolean b = this.cccincoencinco.incrementa(); asserttrue(b); public ContadorCircular(int valor, int incremento, int limite) { this.valor =valor; this.incremento = incremento; this.limite = limite; public ContadorCircular(int limite) { this(0, 1, limite); { public void testcontadorpordefectovuelvealvalorinicialasuperarellimite() this.ccpordefecto.incrementa(); this.ccpordefecto.incrementa(); assertequals(0, this.ccpordefecto.getvalor()); int inicial; public ContadorCircular(int valor, int incremento, int limite) { this.inicial = valor; this.valor =valor; this.incremento = incremento; this.limite = limite; public boolean incrementa() { boolean b = this.valor > this.limite; if (b) { this.valor = this.inicial; return b; public void testresetearcontadorpordefecto() { 9

this.ccpordefecto.incrementa(); this.ccpordefecto.resetea(); assertequals(0, this.ccpordefecto.getvalor()); public void resetea() { this.valor = this.inicial; /* Refactorizamos - Evitamos código repetido */ public boolean incrementa() { boolean b = this.valor > this.limite; if (b) { this.resetea(); return b; 10