¿Qué es un mock y un stub?

Hay muchos blogs y mucha literatura que dan deficiones sobre Mocks, Stubs, Fakes, Dummies… En esta entrada voy a recurrir a las definiciones que da Martin Fowler y voy a tratar de mostrar unos ejemplos prácticos usando Rhino Mock.

 Stub

Los stubs proporcionan respuestas predefinidas a las llamadas realizadas durante la prueba, por lo general no responden en absoluto a nada fuera de lo programado para la prueba. Los stubs también pueden grabar información sobre llamadas, como un código de acceso de correo electrónico que recuerda que se debe dar la salida de los mensajes que se enviaron con ese correo, o tal vez sólo cuántos mensajes fueron enviados.

Un stub por tanto es útil cuando el SUT va a llamar a métodos externos, y se quiere evitar dicha llamada pero se necesita una simulación de la misma, e incluso se puede necesitar obtener una respuesta. Si tienes una clase “Service” que usa métodos de otra clase “Domain”, necesitarás hacer stub sobre esos métodos de “Domain” para mantener tu clase “Service” sometida a pruebas aislada de ese comportamiento. Estarás testeando si Service funciona o no, asumiendo que lo que hay en Domain ofrece un resultado predefinido, sin importar su comportamiento, pues para ello tendrá sus propios unit test.

¿Cómo puedes lograr Stub?

En esta entrada me ceñiré a la librería rhino mock, en el futuro trataré de extender este tema en otras entradas para otras librerías.

En este caso se están generando 2 stubs, que se podrían aplicar dentro de un mismo test. En el primero se obtendrá como resultado a una petición a domain.CountMails(“mail1@test.com”) un resultado de 8, mientras que para domain.CountMails(“mail2@test.com”) se obtendrá un resultado de 10. En ningún caso esa llamada ejecutará la implementación real del método, ni se accederá a base de datos, simplemente se “preprogramará” que si ese método es llamado con alguno de esos 2 argumentos de entrada, se obtendrá un resultado de 8 o 10.

¿Cómo puedes simplemente retornar un valor predefinido, independientemente de las entradas, porque te interesa que así sea para probar tu SUT con independencia de los inputs? De la siguiente manera.

En este caso tienes un Arg<string>.Is.Anything como argumento de entrada de CountMails, por lo tanto, sea cual sea el input, el output será 10.

El test de la clase de servicio ejecutará el método de nuestro SUT (el servicio), y cuando dicho código use el método Stub (cualquiera de los arriba definidos para el domain), obtendrá una respuesta (dependiente o no de los inputs según deseemos), cuando nuestro método SUT haya terminado su ejecución, ofrecerá una salida, y está deberá validarse mediante un Assert. De esta forma estamos testeando nuestro System Under Test (el servicio) de una forma desacoplada a como esté funcionando el dominio, objetivo final de un Stub.

Mock

Los mocks son  objetos preprogramados con expectativas que forman una especificación de las llamadas que se espera recibir.

Un mock va más allá que un stub, un mock te indica algo como “espero que llames a esté método y que si lo haces con un específico argumento de entrada, obtendrás una respuesta concreta”.

Mientras que un Stub es muy útil para probar el “cómo” algo funciona sin demasiada complicación, un mock es algo mas elaborado y esta implicado además de en “cómo” funciona algo, en su comportamiento, en “qué” hace. Es complicado apreciar la diferencia pues es muy sutil, en este hilo sobre Rhino Mock hablo sobre test para probar “cómo” algo se hace, y sobre “qué” hace un método, donde es mas fácil apreciar la diferencia.

¿Cómo puedes lograr Mocks?

A continuación un pequeño ejemplo sobre el uso de un mock con Rhino mock.

En este caso, nuestro SUT no verificará el resultado del test con un Assert, si no con un VerifyAllExpectations.

Mientras que en el stub verificaremos que 8 o 10 son los resultados esperados, en este caso, en el mock, se verificará que GetUser y GetUserRoles son llamados una vez y en ese orden, y sin llamadas intermedias. También se podrá verificar que “UserId” esta relacionado con los resultados esperados, pero no es el objetivo fundamental cuando se aplican mocks con Expect.

Espero que te haya aclarado algo con esa explicación y los ejemplos, aunque entraré en mas detalle sobre Mocks y Stubs en entradas futuras.

Un saludo.

 

2 comentarios en “¿Qué es un mock y un stub?

Deja un comentario