viernes, 3 de septiembre de 2010

PRUEBAS CAJA BLANCA, MOCKITO

PRUEBAS DE CAJA BLANCA

Las pruebas de caja blanca o caja transparente son más exigentes que las de caja negra, ya que se concentran en la forma en que el programa realiza su funcionalidad para lograr el resultado, y no en el resultado en sí.

Para ello se hacen comprobaciones de las comunicaciones entre los objetos, teniendo en cuentra al mismo tiempo los valores que se envían en dichas comunicaciones (parámetros) y los valores de retorno.

Al seguir la metodología TDD con pruebas de caja blanca,el diseño de la aplicación surge de forma natural con las siguientes características:
  1. podemos probar una clase de nuestro programa de forma aislada: es decir no hace falta escribir toda la aplicación para probar (demostrar y saber) que una clase funciona correctamente. Para ello utilizaremos un tipo de objetos vacíos/simulados/falsos denominados Mocks
  2. diseño de clases diferente ya que se descarga la responsabilidad de una clase a otra para poder probarse
  3. el código de los métodos disminuye para y por poder probarse
  4. ...



El framework/librería que utilizaremos para su exposición es Mockito. Otra opción disponible es EasyMock, librería anterior a Mockito.


Mocks

¿qué es un mock?


En la programación orientada a objetos se llaman objetos simulados (pseudoobjetos, mock object, objetos de pega) a los objetos que imitan el comportamiento de objetos reales de una forma controlada. Se usan para probar a otros objetos en pruebas de unidad que esperan mensajes de una clase en particular para sus métodos, al igual que los diseñadores de autos usan un crash dummy cuando simulan un accidente.

En los test de unidad, los objetos simulados suelen usarse para simular el comportamiento de objetos complejos cuando es imposible o impracticable usar al objeto real en la prueba. De paso nos resuelve el problema del caso de objetos interdependientes, que para probar el primero debe ser usado un objeto no probado aún, lo que invalida la prueba: los objetos simulados son muy simples de construir y devuelven un resultado determinado y de implementación directa, independientemente de los complejos procesos o interacciones que el objeto real pueda tener.

Los objetos simulados se usan en lugar de objetos reales que tengan algunas de estas características:

  • Devuelven resultados no determinísticos (por ejemplo la hora o la temperatura)
  • Su estado es difícil de crear o reproducir (por ejemplo errores de conexión)
  • Es lento (por ejemplo el resultado de un cálculo intensivo o una búsqueda en una DB)
  • El objeto todavía no existe o su comportamiento puede cambiar.
  • Debería incluir atributos o métodos exclusivamente para el testeo. (el código de prueba nunca debe existir en la implementación)

Los objetos simulados para imitar al objeto real deben imitar su misma interfaz.

¿para qué se utilizan los objetos mock?

  1. controlar/verificar las llamadas a estos objetos
  2. controlar/verificar los valores que reciben y los valores que devuelven dichos mocks

Mockito
http://code.google.com/p/mockito/


Para utilizar Mockito: instalación

Download mockito-all-x.x.x.jar http://code.google.com/p/mockito/downloads/list e incluir en el classpath del proyecto. Si utilizamos Maven, actualizamos nuestro pom.xml http://code.google.com/p/mockito/wiki/MavenUsers

Caso de uso de ejemplo para explicar Mockito

CODIGO:
class ServicioCarritoCompra{
ServicioMailingUsuario smu=new ServicioMailingUsuario();

String confirmarPedido(Usuario u,Pedido p){
smu.enviaMail(p);
return "Pedido Correcto";
}

Podemos apreciar en el diagrama de secuencia que el método confirmaPedido(usuario, pedido) de la clase ServicioCarrito necesita tener un objeto de la clase ServicioMailing también disponible, ya que al confirmar el pedido se le envía un mail al usuario a través de este ServicioMailing. Esto implica que para usar/probar este metodo necesitamos crear la clase ServicioMailing y a lo mejor esta clase ServicioMailing se apoya en otra clase ServicioConexionServidorCorreoPOP que también tendríamos que escribir... y así sucesivamente hasta que necesitaríamos todo el programa hecho para poder probar un "pequeño" método de una "pequeña" clase

Hay que destacar que lo único que hace (en este caso) el ServicioCarrito en el metodo confirmaPedido es llamar al ServicioMailing... es decir la responsabilidad de este método es únicamente llamar al objeto adecuado con los argumentos adecuados...

Aquí es donde entra la importancia de los objetos Mock o simulados. Ya que podremos probar dicha clase sin tener que escribir ninguna otra implementación. Para ello "mockearemos" el ServicioPedido...

Pasos para usar objetos mock en nuestra clase de prueba

Incluímos el import static de la libreria en nuestra clase de prueba

import static org.mockito.Mockito.*;

Definimos nuestro método de prueba donde vamos a utilizar los mocks

public class ServicioCarritoCompraTest {


@Test
public void confirmacionPedidoEnvioMailingTest(){
//objeto a probar
ServicioCarritoCompra carritoCompra=new ServicioCarritoCompra();


//invocacion
carritoCompra.confirmaPedido(usuario, pedido);



}

creamos los mocks y esperamos
las llamadas a estos objetos

 @Test
public void confirmacionPedidoEnvioMailingTest(){
//objeto a probar
ServicioCarritoCompra carritoCompra=new ServicioCarritoCompra();

ServicioMailing servicioMailingMock=mock(ServicioMailing.class);

UsuarioPedido usuario=new UsuarioPedido();
Pedido pedido=new Pedido();
//invocacion
carritoCompra.confirmaPedido(usuario, pedido);

//comprobacion de resultados y/o comportamientos
verify(servicioMailingMock).enviaMailPedido(pedido);



}


http://code.google.com/p/cea2010-jar/source/detail?r=47


seguimos con el ciclo de pruebas: creamos el código necesario para la compilación y lanzamos la prueba para que falle

http://code.google.com/p/cea2010-jar/source/detail?r=48


se me olvido declarar la relacion entre ambos servicios en la prueba **


http://code.google.com/p/cea2010-jar/source/detail?r=49


seguimos con el ciclo de pruebas: escribimos el código necesario para que la prueba pase
... que la prueba pase, en este caso significa que se verifique la llamada correspondiente

http://code.google.com/p/cea2010-jar/source/detail?r=50

En el ejemplo anterior (y caso de uso) solamente aseguramos que los objetos correspondientes se comunican correctamente con los parámetros correctos...


en el siguiente caso de uso confirmaremos también los valores de retornoTODO:


when(mockedList.get(0)).thenReturn("first");


escribimos la prueba
http://code.google.com/p/cea2010-jar/source/detail?r=51

que compile el codigo
http://code.google.com/p/cea2010-jar/source/detail?r=52

que pase la prueba
http://code.google.com/p/cea2010-jar/source/detail?r=53

con dataprovider
http://code.google.com/p/cea2010-jar/source/detail?r=54


en el siguiente caso de uso confirmaremos el comportamiento ante la captura de excepciones



Como se indica en el diagrama de secuencia la posible excepción que puede lanzar el ServicioStock al invocar el metodo eliminaProductosDeStock(producto1, cantidad1) es transformada por parte del ServicioCarritoCompra en un mensaje a usuario de tipo String

escribimos la prueba
http://code.google.com/p/cea2010-jar/source/detail?r=55

que compile el codigo
http://code.google.com/p/cea2010-jar/source/detail?r=56

que pase la prueba
http://code.google.com/p/cea2010-jar/source/detail?r=57

Exposicion de refactorizacion con creacion de DAO


exposicion en clase de:refactorizar el proyecto picacea para aislar lo relacionado con DB a una clase CatalogoDB.
Quedando el diseño de la siguiente forma:
Controlador _ > DAO____ > CatalogoDB
Teniendo el ~DAO la responsabilidad de la cache, las transacciones, operaciones en cascada

Ejercicio a desarrollar de forma personal


TODO: Para desarrollar las siguientes funcionalidades habrá que definir el escenario de prueba (incluyendo mocks), las invocaciones y los resultados que garanticen el perfecto funcionamiento de la aplicación

  • Un fotografo, una vez que haya seleccionado una lista de fotografias propias, podrá enviar dicha seleccion a un servicio de revelado de copias (ServicioRevelado)

  • Un fotografo, una vez que haya seleccionado una lista de fotografias propias, podrá enviar dicha seleccion a un servicio de revelado de copias (ServicioRevelado), indicando el numero de copias de cada fotografia incluida
  • Un fotografo, una vez que haya seleccionado una lista de fotografias propias, podrá enviar dicha seleccion a un servicio de revelado de copias (ServicioRevelado), indicando el numero de copias de cada fotografia incluida y el tamaño de revelado( tamaño1, tamaño2, tamaño3) de cada fotografia

1 comentario: