PRUEBAS UNITARIAS: ¿MOCK O STUB?

Antes de comenzar con este post, quiero decir que es un placer tener la posibilidad de poder escribir en el blog de Sogeti. Este es mi primer post,  y espero que sea el primero de otros muchos e interesantes. Para empezar he decidido hablar sobre dos tipos de pruebas unitarias: Mock y Stub.

Estos dos tipos de pruebas consisten en crear objetos falsos que sustituyan a los objetos reales y de esta manera poder probar un determinado requerimiento. El objetivo de utilizar objetos fake en lugar de reales, es romper las dependencias con otros objetos y de esta manera probar requerimientos de manera independiente.

Para obtener una definición de Mock y Stub, podemos citar lo que Gerard Meszaros definió en su libro XUnit Test Patterns:

Los Stubs, “proporcionan respuestas predefinidas a ciertas llamadas durante los test, sin responder a otra cosa para la que no hayan sido programados”, es decir, los stubs son configurados para que devuelvan valores que se ajusten a lo que la prueba unitaria quiere probar, por lo que se utilizan para verificar el estado de los objetos.

Los Mocks, “son objetos preprogramados con expectativas que conforman la especificación de lo que se espera que reciban las llamadas”, es decir, son objetos que se usan para probar que se realizan correctamente llamadas a otros métodos, por ejemplo, a una web API, por lo que se utilizan para verificar el comportamiento de los objetos.

Para ver mejor las diferencias entre Mock y Stub vamos a ver unos pequeños ejemplos. En la elaboración de estos ejemplos se ha utilizado Rhino.Mocks, aunque existen otras herramientas comoMoq o NMock.

Para realizar estos ejemplos vamos a suponer que tenemos una tienda virtual en la que a la hora de realizar el pago de algún pedido tenemos la posibilidad de introducir un código de descuento para recalcular el precio total del dicho pedido. Para obtener el descuento en función del código que introduzcamos vamos a llamar a un servicio, el cual nos devolverá el porcentaje de descuento, y con dicho porcentaje se procederá a recalcular el total del pedido.

La interfaz del servicio para obtener el descuento podría ser la siguiente:

ejemplo1

Este método nos devuelve el descuento que se le va a aplicar al total de nuestro pedido en función del código introducido.

Por otro lado, tenemos el método CalculateTotalWithDiscount que consume el servicio, y obtiene el precio final del pedido aplicándole el descuento:

ejemplo2

Ahora vamos a realizar dos test unitarios, un Mock y un Stub para probar el funcionamiento del método CalculateTotalWithDiscount. Con el Mock probaremos que desde este método se hace la llamada al servicio correctamente; y con el Stub probaremos que el resultado es el esperado.

Evidentemente, para realizar los tests no llamaremos al servicio realmente ya que es necesario conseguir aislar el método CalculateTotalWithDiscount de sus dependencias y así comprobar su comportamiento, por lo que será necesario crear objetos que finjan ser el servicio.

El primer test que haremos será el Mock, el cual puede tener el siguiente aspecto:

ejemplo3

Este test está formado por tres bloques, el primer bloque consiste en la generación del mock y la definición de expectativas:

  • En la línea 1, se genera una instancia de la clase que implementa la interfaz IProductService.
  • En la línea 2, se define una expectativa (Expect), lo que significa que, en algún momento sobre el objeto mock creando en la anterior línea se invocará al métodoGetDescointByCode con sus parámetros, en este caso, un parámetro de tipo string, y además, cuando la invocación se haga, el mock devolverá 50.

El siguiente bloque es el de acto (Act), donde llamamos al método que nos recalcula el precio y que a su vez ha de invocar al servicio (en este caso el mock) para que le devuelva el descuento a aplicar.

El último bloque verifica que la expectativa se cumpla, es decir, que la llamada al servicio ficticio se hizo con los parámetros correspondientes. Si no se cumple, entonces el test falla.

Que no se cumpla significa que:

  • La llamada nunca se realizó o que se hizo con otros parámetros distintos a los que explícitamente se pusieron en la expectativa.
  • Se hizo más de una llamada, y en la expectativa sólo se contemplaba una única llamada.
  • En el acto se hagan llamadas al mock que no están contempladas en las expectativas.

Si queremos verificar el estado en lugar del comportamiento utilizaremos los stub, la siguiente prueba muestra un ejemplo.

ejemplo4

La última línea valida que todo fue según lo esperado, comparando el resultado de la llamada al método CalculateTotalWithDicount con el resultado que debería devolver. Si ambos resultados coinciden la prueba se da por correcta.

Una diferencia importante entre los test Stub y Mock es que, en la prueba TestStub no es necesario que se invoque el método GetDescointByCode, ya que pasará como correcta siempre que el precio total del pedido sea igual a 1.5, por el contrario, la prueba TesMock necesita que se invoque al métodoGetDescointByCode para que sea válida.

Por tanto, a la hora de utilizar un test u otro tenemos que preguntarnos que deseamos probar, si necesitamos probar la comunicación entre el cliente y el servicio utilizaremos un Mock, mientras que si sólo necesitamos probar que el resultado que devuelve el método es el que esperamos sin importar las condiciones en lo que lo llamamos, utilizaremos un Stub.

Referencias:

 

Este post ha sido publicado anteriormente en el Innovation Today Blog de Sogeti.

 

Más información:

trinitario gómez

Trinitario Gómez es Ingeniero Técnico en Informática por la Universidad de Alicante. Comenzó su andadura en el mundo de la informática en 2013, año en el que se incorporó a Sogeti como programador junior. Actualmente desarrolla funciones de programador senior  en la unidad de Soluciones Microsoft de Sogeti España.

Conoce más información sobre nuestros servicios de Testing y Calidad de Software aquí.

Anuncios

Deja tu comentario

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: