Cómo hacer Unit Test sobre EF DbContext

En anteriores entradas he presentado mecanismos para hacer Unit Test sobre métodos de lógica genéricos, que suelen ubicarse en una capa de dominio, y Flow Expectation Test sobre la capa de servicio. Ahora voy a presentarte la manera de hacer Unit Test sobre tu capa de datos.

En esta entrada presento una arquitectura que usa un patrón de diseño con Unit Of Work y Reposity Pattern. En esta otra entrada escribí sobre Rhino Mock como una de mis librerías favoritas para Unit Testing. Ahora voy a combinar ambas para hacer unit test a tus métodos de Unit Of Work, pudiendo simular una colección de datos en memoria como si de un acceso a base de datos se tratase, de forma que puedas probar tus métodos con consultas linq y testear así su resultado, siendo capaz de aproximarte cada vez al valioso TDD del que hablo en esta entrada.

En primer lugar he aislado la creación de un contexto mock en una clase que devuelve dicho contexto. En todo momento me voy a basar en mi entrada sobre una arquitectura con esté patrón. Esta clase puede quedar de forma parecida a la siguiente:

La clave de esta clase es su método genérico GetDbSetTestDouble<T>. Este método es capaz de poblar un IDbSet con los datos contenidos en data, de tipo IQueryable, de forma que todas tus consultas de linq serán capaces de hacer querys sobre estos datos.

Para que lo anterior sea posible, en tu clase UnitOfWork los DbSet deben ser definidos como “public virtual IDbSet”.

Ahora lo único que necesitas es definir conjuntos de datos IQueryables por cada objeto de modelo que utilices, y asignarlos como resultado “Return” por cada stub de cada uno de los DbSet contenidos en tu UnitOfWork.

Si tuvieses por ejemplo los siguientes modelos:

  • IdentityRole
  • UserRole

Tu UnitOfWork tendría:

Podrías tener unos objetos IQueryables como:

Ahora en tu método CreateCustomerDataContextTestDouble() debes crear los stub de cada uno de los DbSet, pasando el conjunto de datos al método GetDbSetTestDouble que será usado en el Return de cada stub, quedando como sigue a continuación.

El resultado final sería este:

 

Ya está todo listo, ahora solo queda hacer el test del método que deseas probar. Supongamos que en tu clase de contexto tienes un método que consulta diferentes tablas para obtener un dato, por ejemplo si un usuario tiene un determinado rol por el nombre de dicho rol. Necesitas consultar la tabla IdentityRole y UserRole. Hay muchas formas de abordar esto, pero yo he optado por hacerlo fuera de los repositorios, de forma que estos se mantengan con métodos solo para una tabla, y usar estos métodos con linq en el contexto, en UnitOfWork.

Ahora los siguientes test, aplicarán esta query sobre el contexto el cual tiene los DbSet como Mock gracias a Rhino Mocks, de forma que podrás probar si tus consultas tienen el resultado esperado ante un conjunto de datos que tu has definido, sin necesidad de acceder a la base de datos.

Si quisieses aplicar Includes en tus querys, por tener objetos anidados como podría ser este caso, necesitarás que en tu conjunto de datos, tu objeto padre incluya al objeto hijo definido dentro. Un ejemplo podría ser el siguiente:

Pues otra capa más añadida a tu Code Coverage por Unit Test. Aún estarían sin probar los repositorios contenidos en tu UnitOfWork, pero dado que se trata de una implementación genérica, he preferido probar los repositorios de formas aislada para una entidad concreta, lo cual ya servirá para probar dicha implementación, y en cambio en UnitOfWork aplicar Stub de los repositorios como ya he mencionado en otras entradas, considerándolos un elemento aislado dentro de tu capa de datos que tiene la suficiente entidad por si mismo como para tener sus propios Unit Test.

En breve tendré finalizada esa entrada y podrás complementar a esta, la cual espero que te sea de utilidad.

Un saludo y a disfrutar programando.

Deja un comentario