jueves, 14 de abril de 2011

Implementación de Pruebas Unitarias

Taller de Programación Orientada a Objetos - Semana 11 - Reporte 10

Como mencione la clase anterior mencione para qué funciona el JUnit, lo descargamos y configuramos; ahora voy a utilizarlo para realizar algunas pruebas unitarias en mi código:

1. La clase en la que se implementarán las pruebas unitarias de llama Converter.java.
Los métodos a probar son los siguientes:

Existen dos métodos getStringOfNumber(), la diferencia es que uno recibe un flotante y el otro un entero. Ambos serán probados en el test.

Diseño de la Prueba

Primero importaremos las librerias de nuestro Test JUnit y marcaremos nuestro Test como parte del paquete principal:

Despues programamos el Test.

Estos son los métodos del Test. testUno() se encarga de verificar si efectivamente el valor en letra del entero escrito en la variable String expected es igual a la String result cuyo valor es el que la función getStringOfNumber() esta retornando.

testDos() hace exactamente lo mismo pero con un double.

Incluímos tambien la funcion main() que es la que inicializa el test.

Los resultados fueron variados, mi primer resultado fue utilizando el test assertTrue(), este metodo afirma si una condición es verdadera. Como atributo utilicé la función a.equals(b), la cual compara dos strings y regresa 1 o 0 como valor. Entonces assertTrue recibe dicho valor y si es 1 se pasa el test, si es 0 el test tiene un error.

El testUno() no se paso porque la cadena no es igual. Yo especifique lo siguiente:

137 = CIENTO TREINTA Y SIETE

pero para el test:

137 = CIENTO TREINTA Y SIETE PESOS 0/100 MN.

porque getStringOfNumber() me regresa el valor en letra pero en tipo moneda.

Entonces solo hace falta modificar la variable String expected de testUno() y realizamos la prueba otra vez

Ahora ambos test fuerons pasados.



Saludos :)

miércoles, 13 de abril de 2011

Diseño de Pruebas Unitarias

Programación Orientada a Objetos - Semana 11 - Reporte 10

Mientras desarrollamos una aplicación atravesamos varias fases, pero no hay fase de desarrollo más importante que la fase de pruebas.
Con las pruebas comprobamos que nuestro código realmente haga lo que esperamos y especificamos, y que cumpla con los requerimientos establecidos al inicio.

Las Pruebas Unitarias (Unit Test), se consideran las más importantes para garantizar un proyecto exitoso. Dichas pruebas se encargan de probar clases aisladamente y están relacionadas con el código y responsabilidad de cada clase y sus fragmentos de código más críticos.

Por ejemplo: una clase que sume dos números, y devuelva el resultado. La prueba se encargara de probar el método y verificando que efectivamente sume dos números correctamente y devuelva el resultado correcto.

Ventajas de las Pruebas Unitarias

  • Asegura calidad del código entregado.
  • Es la mejor forma de detectar errores tempranamente en el desarrollo. No obstante, esto no asegura detectar todos los errores, por tanto prueba de integración y aceptación siguen siendo necesarias.
  • Ayuda a definir los requerimientos y responsabilidades de cada método en cada clase probada.
  • Permite encontrar errores o bugs tempranamente en el desarrollo.

Entre muchas otras ventajas, como probar la eficiencia de nuestro código ante el estrés (tiempos de espera y de ejecución).

Proceso

Los pasos para crear pruebas unitarias exitosas son los siguientes:

  • Antes de implementar una determinada funcionalidad, piensa cómo deberías probarla para verificar que se comporta correctamente. Esto permite desarrollar la funcionalidad teniendo las ideas muy claras de lo que debería hacer.
  • Escribe el código que implementa la funcionalidad deseada.
  • Escribe el código de las pruebas inmediatamente después.
  • Ejecuta las pruebas que hiciste.
  • Corrige la unidad de código que implementa la funcionalidad deseada hasta que pase todas y cada una de las pruebas.
  • Al añadir una nueva funcionalidad, repite el ciclo: piensa en cómo probarla, codifica la funcionalidad, codifica las pruebas, ejecuta todas las pruebas que hiciste (nuevas y viejas). No sigas hasta que el código pase absolutamente todas las pruebas.
  • Así una y otra vez para cada nueva funcionalidad que implementes.

JUNIT
JUNIT es un conjunto de clases (framework) 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.

Para realizar su trabajo, JUNIT utilizama métodos ASSERT. Un método Assert es un método de JUnit que realiza una prueba y que retorna un “AssertionFailedError” si la prueba fallo. Para más información sobre dichos métodos visitar las referencias al pie de la entrada.

Configurar JUNIT

1. Descargar el Framework de JUNIT (Descarga directa: [junit4.9b2.zip])
2. Extraer el contenido del paquete.
3. Colocar la carpeta en junit4.9b2 alguna ubicación conocida. (en mi caso /home/juancarlos/)
4. El paso anterior es para configurar el CLASSPATH. Abrimos una terminal, nos aseguramos que estamos en nuestra carpeta personal (en mi caso /home/juancarlos, en su caso /home/sunombredeusuario) y escribimos emacs -nw .bashrc



5. Nos vamos hasta el final del archivo y escribimos la siguiente linea:



Todo es en una sola línea, no poner ningún salto de línea. En el CLASSPATH van escritas las direcciones de las librerias contenidas en 3 archivos .jar. Las tres direcciones van separadas por el caractér de dos puntos ( : ) mas o menos con la siguiente sintaxis:

export CLASSPATH=/UBICACION/junit4.9b2/junit-4.9b2.jar:/UBICACION/junit4.9b2/junit-4.9b2-src.jar:/UBICACION/junit4.9b2/junit-dep-4.9b2.jar:.

Listo, con ello ya hemos ubicado nuestras librerias, ahora podemos comenzar a escribir y compilar pruebas con JUNIT.

IDENTIFICACIÓN DE PRUEBAS

Despues de llenar la factura, se necesita calcular el total a cobrar. Dicho total debe ir escrito en número y letra.
Para obtener el total en número basta con realizar todas las operaciones (suma, resta, multiplicación, división) correctamente. Pero, para obtener el número con letra, el valor debe enviarse a una función y después de procesarlo se debe enviar el valor con letra. Por ejemplo:

1. Se captura una orden, el total a cobrar de dicha orden es de 1535.50
2. El atributo total almacena el valor: orden.total = 1535.50
3. Se genera un nuevo Conversor (clase) y el total de envía a la función llamada getStringOfNumber(float num). getStringOfNumber(orden.total)
4. El método getStringOfNumber regresa una cadena de caracteres (String) que contiene el valor del total en letra.
5. Se espera que getStringOfNumber regrese MIL QUINIENTOS TREINTA Y CINCO PESOS 50/100 M.N

De la misma manera, implementando polimorfismo, hay un método getStringOfNumber() que en lugar de recibir un flotante, recibe un entero.
La finalidad es la misma solo que se trabaja con números de tipo INT (Integer)

REFERENCIAS Y TUTORIALES

martes, 12 de abril de 2011

Implementación de Eventos, Excepcion y Errores propios

Taller de Programación Orientada a Objetos - Semana 10 - Semana 9

Aquí les muestro algunas capturas de pantalla implementando eventos y excepciones.

EVENTOS
Todos mis eventos están orientados a la interfaz gráfica, es por ello que les muestro como quedarían algunos de mis eventos implementando una de las barras de herramientas.

Implementación en el Código





Ejecución



EXCEPCIONES

1. Comenzamos por analizar los menús; cuando entramos a un menú en pantalla, hay que elegir una opción válida. Las opciones válidas son números dentro del rango permitido (el rango esta dado por el número total de opciones). Si se elige una opción fuera de ese rango ocurrirá una excepción y se imprimirá un mensaje en pantalla. De igual forma, si se introduce un carácter, espacio, salto de línea, tabulación, etcétera; como opción, se mostrará un mensaje de error también.

Implementación en el Código



Ejecución


2. Después de que elegimos una opción, hay que cargar los datos de la empresa. Los datos de la empresa están almacenados en un archivo de sistema el cual hay que leer.
Aquí puede ocurrir otra excepción, cuando el archivo no es encontrado. Si eso pasa, se muestra un mensaje de excepción y no se puede realizar ninguna factura.

Impementación en el Código







Ejecución

3. Cuando se toman los datos del concepto a facturar, hay campos en los que forzozamente hay que introducir un valor númerico, tal es el caso del precio y la cantidad de artículos de un solo tipo. En este caso se implementa un NumberFormatException.
Si ocurre la excepción, es decir, se introdujo como valor un caractér, un espacio, tabulacion o salto de línea, cualquier cosa menos un número; se mostrará un mensaje de excepción y se pedirá el valor de nuevo.

Implementación en el Código
Ejecución

Espero les sirva la información de esta entrada.

Suerte :)

miércoles, 6 de abril de 2011

Identificación de Eventos, Excepciones y Errores propios

Programación Orientada a Objetos - Semana 10 - Reporte 9

Cuando diseñamos una aplicación todos estamos expuestos a los errores y las excepciones. De la misma forma, generamos eventos que nos sirven para realizar diversas acciones dentro de nuestro programa.

EVENTOS


Los eventos, como ya mencioné, son acciones que el usuario inicia y que el programa procesa regresando un resultado, lo que se conoce como respuesta (por lo general, aunque no siempre).
En java, la clase padre de todo tipo de eventos es la clase java.awt.Event

Algunos tipos de eventos son:

- KeyEvent: se produce cuando el usuario presiona alguna tecla.
- MouseEvent: cuando el usuario mueve el mouse o presiona alguno de los botones del mismo.
- WindowEvent: son eventos relacionados con las ventanas de la aplicación, ejemplos pueden ser abrir la ventana o cerrarla.
- ActionEvent: son eventos variados, acciones que se realizan sobre los componentes de la aplicación, por ejemplo el presionar un botón.
- TextEvent: relacionados al texto, se producen por ejemplo al cambiar el texto que ingresamos.

Java captura los eventos utilizando interfaces de escucha o Listeners. Para cada tipo de evento hay una interfaz de escucha:

- MouseEvent , MouseListener
- ActionEvent , ActionListener.


EXCEPCIONES


Las excepciones son situaciones eventuales que pueden presentarse dentro del tiempo de ejecución de nuestro programa, por lo general, una excepción la podemos identificar antes de tiempo y así programar la manera en la que nuestro programa deberá capturarla y gestionarla. Tras capturar la excepción, es posible, si así se desea, continuar desde el punto donde se produjo la excepción.

Las hay de dos tipos:

- RuntimeException: errores en el tiempo de ejecución. Son causadas por los programadores, por ejemplo, si se divide entre cero o se intenta acceder mas allá de la memoria reservada para un arreglo.

- IOException: errores de entrada y salida. Por ejemplo, intentar accesar o modificar archivos inexistentes, o sin el permiso requerido.

Cuando se produce un error, se genera un objeto Throwable. Los objetos Throwable contienen un mensaje (String) que almacena una descripción del error; la pila de memoria (stack) existente al momento de generar el objeto y la causa, tambien de tipo Throwable con la que podemos presentar el error en sí.

Las excepciones se capturan mediante los bloques try - catch. Cada sentencia try debe ir seguida de una sentencia catch, y cada método o clase puede indicar el tipo de objeto Throwable a lanzar. Por ejemplo:

public void function () throws IOException {
...
// código libre de excepciones
...
try {
...
// código que posiblemente lance una excepción
...
} catch (IOException error) {
...
// qué hacer en caso de excepción
...
}
}

ERRORES


Los errores por lo general, van más allá de nuestro alcance. Son situaciones criticas que no podemos manejar de forma habitual, incluso, no deberíamos intentar capturarlas y gestionarlas. Indican otro tipo de fallos de los cuales no podemos recuperarnos y solo queda finalizar la ejecución del programa.

Los errores más tipicos hacen referencia a fallos del sistema:

- Memoria agotada.
- Accesar a espacios ya reservados, por otros programas, en la memoria.
- Sobrecarga del procesador.
- Perdida de la conexión a base de datos, internet.
- Problemas de hardware.

Por lo general este tipo de errores deben visualizarse antes que todo, es decir, verificar las capacidades del sistema al cual orientamos nuestro programa, evitar errores en la lógica de la aplicación que causen ciclos o procesos infinitos que sobrecarguen el sistema, etcétera.

Errores y excepciones detienen la ejecución normal de nuestro código, los errores son los únicos que pueden forzarnos a cerrar nuestra aplicación, en cambio, las excepciones, nos permiten continuar la ejecución normal de nuestro código sabiendo manejar dichas excepciones de forma correcta.

IDENTIFICACIÓN DE EVENTOS, ERRORES Y EXCEPCIONES EN MI PROYECTO.

Eventos propios.

La gran mayoría de mis eventos estarán enfocados a la interfaz gráfica, más que nada al tipo ActionEvent ya que colocare una gran cantidad de botones en algo que emulará una barra de herramientas.

Además incluiré varios eventos de tipo TextEvent, estos eventos notificarán a mi aplicación cuando los datos de una factura que vaya ingresando sean modificados.


Excepciones.

Muchas excepciones han sido previstas por mi código. Comenzando por las básicas que son las de entrada y salida.
Dentro de los menús principal y secundarios: ¿Estás eligiendo una opción válida?. De no ser así, se produce una excepción con un mensaje y se vuelve a dar la oportunidad de elegir la opción válida.



Dentro del módulo de facturación, lo primero que se hace es cargar los datos de la empresa (proveedor, supplier), guardados en un archivo: ¿Existe el archivo? ¿Es el correcto?. Si no es así, la excepción permite llenar un segundo archivo correcto y es el que se procede a cargar. El primer archivo, de estar ahí, se convierte en basura y el segundo se convierte en el archivo correcto.



En el módulo de facturación, al crear nueva factura hay que pedir los datos: ¿Es el tipo de dato correcto? Esto más que nada se produce al pedir cantidades numéricas, por ejemplo precios o cantidad de artículos. Te pido un Integer o Double, pero me das un carácter; la excepción muestra un mensaje y te permite dar otro valor.




En la base de datos. ¿Se pudo abrir la base de datos? ¿Se pudo guardar el dato? ¿Se pudo accesar a los datos?. La excepción mostrara un mensaje según corresponda.

Errores

Hasta ahora no tengo ningún error previsto, pero algunos de ellos pueden ser:

En la lista de artículos de la factura, la lista es tan grande que te haz quedado sin memoria.
La interfaz gráfica es muy pesada o elaborada, algunos sistemas no pueden cargarla ocasionando la finalización del programa.
El iterador, al leer los nodos de la lista siguió un ciclo infinito y sobrecarga el procesador.
Hemos usado comandos de sistema y el código no es portable, ocasionando errores de compatibilidad.
Librerías que no están presentes ocasionando errores de ejecución y el mal funcionamiento de ciertas partes del código.


Referencias