Si desea utilizar TDD (o cualquier otro enfoque de prueba con cobertura de prueba alta) y EF juntos, debe escribir pruebas de integración o de extremo a extremo. El problema aquí es que cualquier enfoque con burla de contexto o repositorio solo crea una prueba que puede probar la lógica de capa superior (que usa esos simulacros) pero no su aplicación.
ejemplo simple:
Definamos repositorio genérico:
public interface IGenericRepository<TEntity>
{
IQueryable<TEntity> GetQuery();
...
}
Y permite escribir algún método de negocio:
public IEnumerable<MyEntity> DoSomethingImportant()
{
var data = MyEntityRepo.GetQuery().Select((e, i) => e);
...
}
Ahora bien, si te burlas del repositorio que va a utilizar LINQ-to- Objetos y tendrá una prueba verde, pero si ejecuta la aplicación con Linq-To-Entities obtendrá una excepción porque seleccionar sobrecarga con índices no es compatible con L2E.
Este fue un ejemplo simple, pero puede ocurrir lo mismo con el uso de métodos en consultas y otros errores comunes. Además, esto también afecta a métodos como Agregar, Actualizar, Eliminar generalmente expuestos en el repositorio. Si no escribe un simulacro que simule exactamente el comportamiento del contexto EF y la integridad referencial, no pondrá a prueba su implementación.
Otra parte de la historia son los problemas con la carga diferida que tampoco se puede detectar con las pruebas unitarias contra los simulacros.
Por lo tanto, también debe introducir pruebas de integración o de extremo a extremo que funcionen contra una base de datos real utilizando el contexto EF real ane L2E. Por cierto. es necesario utilizar pruebas de extremo a extremo para usar TDD correctamente. Para escribir pruebas de extremo a extremo en ASP.NET MVC, puede WatiN y posiblemente también SpecFlow para BDD, pero esto realmente agregará mucho trabajo pero tendrá su aplicación realmente probada. Si desea leer más sobre TDD, recomiendo this book (la única desventaja es que los ejemplos están en Java).
Las pruebas de integración tienen sentido si no utiliza el repositorio genérico y oculta sus consultas en alguna clase que no exponga IQueryable
pero devuelve datos directamente.
Ejemplo:
public interface IMyEntityRepository
{
MyEntity GetById(int id);
MyEntity GetByName(string name);
}
Ahora usted puede simplemente escribir pruebas de integración para probar la implementación del este repositorio porque las consultas se esconden en esta clase y no expuestos a las capas superiores. Pero este tipo de repositorio se considera de alguna manera como una implementación antigua utilizada con procedimientos almacenados. Perderá muchas funciones de ORM con esta implementación o tendrá que hacer un montón de trabajo adicional; por ejemplo, agregue specification pattern para poder definir consultas en la capa superior.
En ASP.NET MVC puede reemplazar parcialmente las pruebas de extremo a extremo con pruebas de integración en el nivel del controlador.
Editar basado en comentario:
No digo que necesita pruebas unitarias, pruebas de integración y pruebas de extremo a extremo. Digo que hacer aplicaciones probadas requiere mucho más esfuerzo. La cantidad y tipos de pruebas necesarias dependen de la complejidad de su aplicación, el futuro esperado de la aplicación, sus habilidades y habilidades de otros miembros del equipo.
Los proyectos pequeños y sencillos se pueden crear sin pruebas (bueno, no es una buena idea, pero todos lo hicimos y al final funcionó) pero una vez que un proyecto pasa un umbral puedes encontrar que presenta nuevas características o mantener el proyecto es muy difícil porque nunca está seguro de si rompe algo que ya funcionó; eso se llama regresión. La mejor defensa contra la regresión es un buen conjunto de pruebas automatizadas.
- Las pruebas de unidades lo ayudan a probar el método. Tales pruebas idealmente deberían cubrir todas las rutas de ejecución en el método. Estas pruebas deben ser muy breves y fáciles de escribir; una parte complicada puede ser configurar dependencias (mocks, faktes, stubs).
- Las pruebas de integración lo ayudan a probar la funcionalidad en múltiples capas y generalmente a través de múltiples procesos (aplicación, base de datos). No necesita tenerlos para todo, se trata más de experiencia para seleccionar dónde son útiles.
- Las pruebas de extremo a extremo son algo así como la validación de la historia/función del caso de uso/usuario. Deben cubrir todo el flujo del requisito.
No es necesario probar una función varias veces: si sabe que la característica se prueba en una prueba de extremo a extremo, no necesita escribir la prueba de integración para el mismo código. Además, si sabe que el método tiene solo una ruta de ejecución única que está cubierta por la prueba de integración, no necesita escribir una prueba de unidad para ella. Esto funciona mucho mejor con el enfoque TDD donde se comienza con una gran prueba (extremo a extremo o integración) y se profundiza en las pruebas unitarias.
Dependiendo de su enfoque de desarrollo, no tiene que comenzar con varios tipos de prueba desde el principio, pero puede presentarlos más adelante ya que su aplicación se volverá más compleja. La excepción es TDD/BDD donde debería comenzar a usar al menos las pruebas de extremo a extremo y de unidad antes incluso de escribir una sola línea de otro código.
Así que usted está haciendo la pregunta incorrecta. La pregunta no es ¿qué es más simple? La pregunta es: ¿qué te ayudará al final y qué complejidad se adapta a tu aplicación? Si desea tener una lógica de aplicación y lógica comercial probada de forma sencilla, debe ajustar el código EF a otras clases que pueden ser objeto de burla. Pero al mismo tiempo, debe introducir otro tipo de pruebas para asegurarse de que el código EF funcione.
no se puede decir qué enfoque se ajuste a su entorno/proyecto/equipo/etc, pero me puede explicar ejemplo de mi pasado proyecto:
que trabajaron en el proyecto durante unos 5-6 meses con dos colegas. El proyecto se basó en ASP.NET MVC 2 + jQuery + EFv4 y se desarrolló de forma incremental e iterativa. Tenía mucha lógica de negocios complicada y muchas consultas de bases de datos complicadas. Comenzamos con repositorios genéricos y alta cobertura de código con pruebas unitarias + pruebas de integración para validar el mapeo (pruebas simples para insertar, eliminar, actualizar y seleccionar entidad). Después de algunos meses, descubrimos que nuestro enfoque no funciona. Tuvimos más de 1.200 pruebas unitarias, cobertura de código de aproximadamente 60% (que no es muy buena) y muchos problemas de regresión.Cambiar cualquier cosa en el modelo EF podría presentar problemas inesperados en partes que no se tocaron durante varias semanas. Descubrimos que nos faltan pruebas de integración o pruebas de extremo a extremo para nuestra lógica de aplicación. La misma conclusión se tomó sobre un equipo paralelo que trabajó en otro proyecto y el uso de pruebas de integración se consideró como recomendación para nuevos proyectos.
Dijiste repositorios añaden 'complejidad' a su aplicación, pero yo diría que son una 'carga' inicial que facilita las pruebas. Burlarse de algunos repositorios es más fácil que burlarse de un contexto de datos completo. – Omar
Sí, pero no quiero esa sobrecarga inicial en mi caso actual. Quiero progresar con la aplicación rápidamente. Ya perdí demasiado tiempo sin ningún progreso real. Agregar repositorios trae cosas como IoC, DI, etc. y tendré que escribir un montón de pruebas antes de llegar a la primera Vista. Sé que esta podría ser la solución correcta, pero no estoy buscando "la correcta". Estoy buscando una solución simple (aunque todavía comprobable). – Damb