15 abr 2011

Implementación de pruebas unitarias

Taller de Programación Orientada a Objetos 
Semana 11 

Implementación de las pruebas unitarias en código documentado y un reporte de los resultados de su ejecución.

14 abr 2011

Diseño de pruebas unitarias

Programación Orientada a Objetos 
Semana 11 

Esta entrada es referente a las pruebas unitarias que estamos por aplicar a nuestro proyecto. Primeramente tenemos que conocer que es una prueba unitaria en la materia de programación, y es que esta es una manera de probar si una parte de nuestro código funciona correctamente. Con esto nos podemos asegurar que cada una de los métodos de una clase funcionen correctamente individualmente.

La principal razón por la que se escriben pruebas para cada función o método en una clase, es para que su buen funcionamiento sea independiente de las otras.

Con lo que debe cumplir una prueba unitaria para considerase buena debe seguir por lo menos los siguientes requisitos:

Automatizable: No debería requerirse una intervención manual.

Completas: Deben cubrir la mayor cantidad de código.

Reutilizables: No se deben crear pruebas que sólo puedan ser ejecutadas una sola vez.

Independientes: La ejecución de una prueba no debe afectar a la ejecución de otra.

El objetivo de una prueba unitaria es comprobar que partes individuales del código funcionan correctamente.

Las ventajas que nos brindan las pruebas unitarias son:

Fomentan el cambio: Las pruebas unitarias facilitan que el programador cambie el código para mejorar su estructura, puesto que permiten hacer pruebas sobre los cambios y así asegurarse de que los nuevos cambios no han introducido errores.

Simplifica la integración: Puesto que permiten llegar a la fase de integración con un grado alto de seguridad de que el código está funcionando correctamente.

Documenta el código: Las propias pruebas son documentación del código puesto que ahí se puede ver cómo utilizarlo.

Separación de la interfaz y la implementación: Dado que la única interacción entre los casos de prueba y las unidades bajo prueba son las interfaces de estas últimas, se puede cambiar cualquiera de los dos sin afectar al otro.

Los errores están más acotados y son más fáciles de localizar: Dado que tenemos pruebas unitarias que pueden desenmascararlos.

Otra ventaja de las pruebas unitarias es que nos da más confianza para modificar código ya que se pierde el miedo a hacer modificaciones y volver inconsistente el sistema.

Según el tipo de componente, podemos probar varios aspectos del código:
Funciones individuales o métodos de objeto: Probar las entradas y las salidas y comprobar que los valores obtenidos son los esperados.

Clases de objetos: Hacer pruebas aisladas de operaciones o probar también las secuencias de las operaciones.

Componentes: Hay que tener en cuenta si son distribuidos, en este caso es recomendable pasarle al componente pruebas de estrés.

¿Donde ejecutamos las pruebas unitarias?
En java podemos usar JUnit para las pruebas unitarias y JMeter para pruebas de rendimiento. Para otros lenguajes existen herramientas similares.


JUnit es un conjunto de clases que permite realizar la ejecución de clases Java de manera controlada, para poder evaluar si el funcionamiento de cada uno de los métodos de la clase se comporta como se espera. Es decir, en función de algún valor de entrada se evalúa el valor de retorno esperado; si la clase cumple con la especificación, entonces JUnit devolverá que el método de la clase pasó exitosamente la prueba; en caso de que el valor esperado sea diferente al que regresó el método durante la ejecución, JUnit devolverá un fallo en el método correspondiente.

Yo descargue JUnit desde el siguiente enlace:

Descargas

En la página hay varios paquetes, yo recomiendo bajar el más reciente que hasta el momento es el credo el 18 de enero de este año.

Crear nuestros propios Tests

En el enlace anterior esta una página de ayuda con un ejemplo simple de como empezar con JUnit y la creación de tests.

¿Cuándo implementamos las pruebas unitarias?
De forma paralela a la codificación o antes de la codificación siguiendo un desarrollo guiado por pruebas.

Referencias:
Prueba unitaria
Pruebas en el Software

12 abr 2011

Implementación de eventos, excepciones y errores

Taller de Programación Orientada a Objetos 
Semana 10 

Incorporación de eventos, excepciones y errores particulares del software.

Excepciones

Pequeños bloques de try y catch de mi código.

Con el manejo de archivos:
try {
  out = new FileOutputStream("Datos01.dat");
  p = new PrintStream(out);
  p.println("Tabla nueva");
  p.close();
} catch (Exception e) {
  System.err.println("Error con el archivo");
}

try {
  FileInputStream fstream = new FileInputStream(project/01.dat);
  DataInputStream in = new DataInputStream(fstream);

  while (in.available() !=0) {
    System.out.println(in.readLine());
  }
  in.close();
} catch (Exception e) {
  System.err.println("Error al crear");
}

En la entrada de datos:
public EntradaDatos() {
  InputStreamReader entrada = new InputStreamReader(System.in);
  BufferedReader br = new BufferedReader(entrada);
  try {
    System.out.println("Dime tu nombre:");
    nombre = br.readLine();
    System.out.println("Dime cuanto daras:");
    valor = Double.parseDouble(br.readLine());
  } catch(Exception e)  {
    e.printStackTrace();
  }
}

Identificación de eventos, excepciones y errores

Programación Orientada a Objetos 
Semana 10 

Texto con diagramas que explica los eventos, excepciones y errores particulares al software que está diseñando.

Eventos
En Java, los eventos representan toda la actividad que tiene lugar entre el usuario y la aplicación. Abstract Windowing Toolkit (AWT) comunica estas acciones a los programas de uso de eventos. Cuando el usuario interactúa con un programa digamos haciendo clic en un botón de comando, el sistema crea un evento que representa la acción y delega en el código de control de eventos dentro del programa. Este código determina la forma de controlar el evento por lo que el usuario obtiene la respuesta adecuada.

Existen varios grupos de eventos comunes en programas creados en Java, como pueden ser:
Eventos de la ventana.
Eventos del teclado.
Eventos del ratón.
Eventos de las barras de desplazamiento.

Para que un evento logre hacer la acción para la cual se le programo, es necesario tener un escuchador que este al pendiente de las acciones del usuario, y este responda inmediatamente de alguna forma.

> Como todo programa que incluye una interfaz gráfica como eventos de mi proyecto tendré una ventana que responderá a los botones de la esquina superior y marcan el cierre o la acción de minimizar la ventana.

> Como en mi programa se necesita que el usuario llene algunos campos se tiene que tener un escuchador para el teclado, que este recibiendo datos del teclado.

> Y el escuchador para los botones de la ventana principal, también requiere del escuchador.

Estos será los eventos que tendría tomados en cuenta en mi programa.

Excepciones
Una excepción es un evento, que se produce durante la ejecución de un programa, que interrumpe el flujo normal de las instrucciones del programa.

Cuando se produce un error dentro de un método, el método crea un objeto y lo entrega al sistema en el tiempo de ejecución. El objeto, llamado un Objeto de Excepción, contiene información sobre el error, incluyendo su tipo y el estado del programa cuando se produjo el error. A la creación de un objeto de excepción y la entrega al sistema en el tiempo de ejecución se denomina una excepción.

El sistema de ejecución busca en la pila de llamadas de un método que contiene un bloque de código que puede controlar la excepción. Este bloque de código que se llama un controlador de excepciones. La búsqueda se inicia con el método en el que se produjo el error y procede a través de la pila de llamadas en el orden inverso en el que los métodos fueron llamados.

Existen tres tipos de excepciones:
El primer tipo de excepción es la excepción comprobada. Estas son condiciones excepcionales que una aplicación bien escrita debe anticipar y recuperarse. Por ejemplo, si se le pide al usuario indicar el nombre de un archivo que se desea abrir, y se comete un error en la escritura del archivo y este no existe, entonces el programa deberá lanzar un aviso de error en la escritura del nombre del archivo.

El segundo tipo de excepción es el error. Estas son condiciones excepcionales que son externos a la demanda, y que la aplicación por lo general no puede anticipar o recuperarse. Por ejemplo, si es necesario abrir un archivo para que el programa haga determinada acción y por fallas en el sistema o hardware este archivo no se puede abrir, estaríamos enfrentando este tipo de error.

El tercer tipo de excepción es la excepción en tiempo de ejecución. Estas son condiciones excepcionales que son internos a la demanda, y que la aplicación por lo general no puede anticipar o recuperarse. Estos por lo general indican errores de programación, tales como errores de lógica o el uso indebido de una API.

El primer paso en la construcción de un controlador de excepciones es encerrar el código que podría lanzar una excepción dentro de un try.

Para asociar controladores de excepciones con try al proporcionar una o más bloques catch inmediatamente después de la try de bloque. Ningún código puede estar entre el final de las try de bloque y el comienzo de la primera catch de bloque.

try {

} catch (ExceptionType name) {

} catch (ExceptionType name) {

}

Errores
EL error es un tipo de excepción que no se puede anticipar y por lo general termina cerrando el programa. Lo ideal es avisar al usuario que se deberá cerrar el programa por completo, y evitar que el programa se cierre frente a los ojos del usuario sin darle previo aviso.

> En mi caso, si al abrir el programa se detecta un error que impide abrir correctamente el programa, este deberá cerrarse inmediatamente.

> También se puede esperar a que en el momento de la ejecución del programa un evento deje de escuchar las peticiones por falla en el sistema mismo, este deberá mandar el error y avisar del cierre próximo del programa.

Referencias:
Java Exceptions
Eventos en Java

31 mar 2011

Aplicación de patrones de diseño

Taller de Programación Orientada a Objetos 
Semana 9 

Incorporación de patrones de diseño en la implementación del proyecto.

Identificación de patrones de diseño

Programación Orientada a Objetos 
Semana 9 

Para esta semana el trabajo a entregar es un texto con diagramas que explique cuáles patrones se aprovechan en nuestro proyecto.

Algunas personas definen un patrón como una solución recurrente para un problema en un contexto. Primero, un contexto es el entorno, situación, o condiciones interrelacionadas dentro de las cuales existe algo. Segundo, un problema es una cuestión insatisfecha, algo que se necesita investigar y resolver. Un problema se puede especificar mediante un conjunto de causas y efectos. Normalmente un problema está restringido al contexto en el que ocurre. Finalmente, la solución se refiere a la respuesta al problema dentro de un contexto que ayuda a resolver las dificultades.

Entonces, si tenemos una solución a un problema en un contexto, ¿Será este un patrón? No necesariamente. También necesitamos asociar la característica de recurrencia con la definición de un patrón. Los patrones deberían comunicar soluciones de diseño a los desarrolladores que los leen y los utilizan. Como puedes ver, aunque el concepto de patrón es bastante simple, definir realmente el término es muy complejo.

Abstracción de patrones
Un patrón describe, con algún nivel de abstracción, una solución experta a un problema. Los patrones solucionan problemas que existen en muchos niveles de abstracción. Hay patrones que describen soluciones para todo, desde el análisis hasta el diseño y desde la arquitectura hasta la implementación.

Identificar un patrón
Se han manejado muchos proyectos J2EE en Sun Java Center, y, con el tiempo, se ha notado que ocurren problemas similares en todos estos proyectos. También se ha visto que han emergido soluciones similares para todos estos problemas. Aunque las estrategias de implementación variaran, las soluciones generales eran bastante similares.

Cuando se ha visto un problema y una solución recurrentes, se ha intentado identificar y documentar sus características usando la plantilla de patrón. También se emprendió el procesamiento de significado de los patrones buscando patrones en soluciones ya implementadas.

Muchas veces, soluciones similares podrían representar un sólo patrón. Cuando se decide cómo formar un patrón, es importante considerar cual es la mejor forma de comunicar la solución. Algunas veces, un nombre independiente mejora la comunicación entre los desarrolladores. Si es así, es mejor considerar la documentación de dos soluciones similares como dos patrones diferentes.

Existen tres categorías de patrones de diseño de acuerdo a su propósito, y son los siguientes:

Creacionales: Inicialización y configuración de objetos.

Estructurales: Separan la interfaz de la implementación. Se ocupan de cómo las clases y objetos se agrupan, para formar estructuras más grandes.

Comportamiento: Más que describir objetos o clases, describen la comunicación entre ellos.

En cuanto a mi proyecto muestro cuales patrones creo que me servirían implementar y les explico el porque creo que me ayudan de alguna forma.

Patrón creacional: Builder

El patrón Builder es usado para permitir la creación de una variedad de objetos complejos desde un objeto fuente, el objeto fuente se compone de una variedad de partes que contribuyen individualmente a la creación de cada objeto complejo a través de un conjunto de llamadas a interfaces comunes de la clase Abstract Builder.

Abstrae el proceso de creación de un objeto complejo, centralizando dicho proceso en un único punto, de tal forma que el mismo proceso de construcción pueda crear representaciones diferentes.

Diagrama de ejemplo:


Algunas ventajas:
  • Varia la representación interna de estructuras compleja, respetando la interfaz común.
  • Se independiza el código de construcción de la representación.
  • Evita el acoplamiento.
  • Cada ConcreteBuilder tiene el código especifico para crear y modificar una estructura interna concreta.
  • Permite un mayor control en el proceso de creación del objeto.

¿Porqué creo se aplica a mi proyecto?
En mi proyecto cada clase se encarga de crear un objeto diferente, por ejemplo una crea la ventana con ciertas opciones, la clase de registro muestra en un label un cuadro con la información almacenada en los registros guardados, otro crea una gráfica y la inserta en un label que remplazaría al de registros.

Patrón estructural: Composite

El patrón Composite describe un grupo de objetos deben ser tratados de la misma manera que una sola instancia de un objeto. La intención de un compuesto es la de "componer" objetos en estructuras de árbol para representar jerarquías parte-todo. Aplicación del modelo compuesto permite a los clientes tratar objetos individuales y composiciones de manera uniforme

Composite puede ser utilizado cuando los clientes deben pasar por alto la diferencia entre las composiciones de objetos y objetos individuales. Si los programadores encuentran que están utilizando varios objetos de la misma manera, y con frecuencia tienen casi idéntico código para manejar cada uno de ellos, entonces este patrón es una buena opción, es menos complejo en esta situación para tratar primitivos y compuestos como homogéneos.

Diagrama de ejemplo:


Patrón de comportamiento: Mediator

Un Mediator es un patrón de diseño que coordina las relaciones entre sus asociados. Permite la interacción de varios objetos, sin generar acoples fuertes en esas relaciones.

Cuando muchos objetos interactúan con otros objetos, se puede formar una estructura muy compleja, con objetos con muchas conexiones con otros objetos. En un caso extremo cada objeto puede conocer a todos los demás objetos. Para evitar esto el patrón Mediator encapsula el comportamiento de todo un conjunto de objetos en un solo objeto.

Usar el patrón Mediator cuando:
Un conjunto grande de objetos se comunica de una forma bien definida, pero compleja.
Reutilizar un objeto se hace difícil por que se relaciona con muchos objetos.
El comportamiento de muchos objetos que esta distribuido entre varias clases, puede resumirse en una o varias por subclasificación.

¿Porqué se aplica a mi proyecto?
Mi proyecto necesita la interacción entre clases para la creación de los objetos en una ventana, y para evitar sobrecargar el sistema este serviría para esto ya que evitaríamos tener que estar regresando a la clase principal para crear todos los objetos nuevamente, ya que por ejemplo en la clase Gráfica se crea la gráfica pero mi idea es no quitar de vista las opciones de la ventana mostrada anterior a esta.

Diagrama de ejemplo:


Ventajas y desventajas:
Simplifica la comunicación entre objetos: Los objetos que se comunican de la forma "muchos a muchos" puede ser remplazada por una forma "uno a muchos" que es menos compleja y más elegante.
Abstrae como los objetos cooperan: Haciendo a la mediación un concepto independiente y encapsulandolo en un objeto permite enfocar como los objetos interactúan. Esto ayuda a clarificar como los objetos se relacionan en un sistema.
Centraliza el control: El mediador es el que se encarga de comunicar a los colegas, este puede ser muy complejo, difícil de entender y modificar.

Bibliografía:
Patrones de diseño en Java
¿Qué es un patrón de diseño
Builder | Composite | Mediator