Mock and stub – Sobre arquitecturas de UnitOfWork con Reposity pattern

Una de mis primeras entradas al crear este blog, fue sobre una arquitectura sobre la capa de datos usando Unit Of Work, Repository Pattern y EntityFramework Code First, con el objetivo de desacoplar tu capa de datos del resto de las capas de tu aplicación donde está contenida la lógica, servicios, negocio…

Un objetivo derivado, al conseguir este desacople, es poder aplicar Mocks y Stubs sobre tu capa de datos. Mock a estas clases de unit of work y repository, haciendo stub sobre sus métodos de forma que los unit test sobre las capas superiores se mantengan siendo atómicos, independientes de la capa de datos, y por tanto mucho más rápidos que si deben acceder a estos datos. Esto por otra parte facilita una aproximación F.I.R.S.T de los unit test como menciono en otra entrada.

Si analizas mi entrada sobre Unit Of Work, podrás ver que en los repositorios existe un método Add para añadir una entidad al contexto de datos para posteriormente mediante un SaveContext ser persistida en la base de datos. Tu código por tanto contendrá en tu capa de dominio líneas de código como esta:

En esta clase BusinessDomainService se ha creado dependencia por DI con IBusinessContext, que es el contexto que está heredando de Unit Of Work, el cual a su vez contiene el BusinessRepository que se está usando para hacer Add en el método RegisterBusiness.

Por lo tanto, de acuerdo al código anterior, para probar el método RegisterBusiness con unit test, necesitaremos hacer mock de businessRepository para hacer stub de Add, y a su vez hacer mock de businessContext para hacer stub de BusinessRepository para asignarle el mock de businessRepository creado.

Esto quedaría de la siguiente manera:

En el test, estamos usando RegisterBusiness, que dentro llamará a businessContext que usará el repositorio, ambos están mockeados y los métodos usados tienen stubs para condicionar una respuesta controlada, de forma que el test es atómico asumiendo un comportamiento adecuado de las dependencias a través de los stubs.

En mi entrada sobre Mocks y stubs escribí el siguiente código como ejemplo de un stub:

En este caso en cambio, el stub no contiene esa sintaxis de RhinoMocks.Constraints “Arg<string>.Is.Equal(“mail1@test.com”)”. En esa entrada hablo que de esta forma podemos condicionar diferentes respuestas para diferentes parametros de entrada, en este caso dependiendo de tener mail1 o mail2 ofreceremos como respuesta un 8 o un 10 respectivamente.

En el caso del ejemplo que acabo de plantear, no nos importa cual sea el parametro de entrada. Una posible forma de representar esta situación es indicar null en el parametro y posteriormente indicar que no nos importan los argumentos de entrada para ofrecer una respuesta o simplemente controlar la llamada con el stub, de forma que no se llame a la implementación real.

En este caso, el mismo método devolverá siempre 8, indistintamente de cual sea el mail del parámetro de entrada.

Además, en el caso del businessContext, estamos introduciendo que siempre que la propiedad BusinessRepository sea llamada, se devuelva el objeto businessRepository que ya es un mock y tiene stub de su método Add.

Pues listo, ya puedes encontrar en este blog:

  • Flow expectation test sobre la capa de servicio con rhino mocks, incluyendo mock, stub y expectations de la capa de dominio
  • Unit test sobre la capa de dominio con rhino mocks, incluyendo mock y stub de la capa de datos
  • Unit test sobre la capa de datos con rhino mocks para hacer mock de contextos de EF

En próximas entradas escribiré sobre unit test en los controladores, así como integration test en esos controladores para hacer una prueba end-to-end salvando solo mediante mock y stub las dependencias sobre servicios externos, de forma que toda la lógica de tu servicio sea testeada end-to-end como digo.

Deja un comentario