work unit test repositorio pattern patrón parte net mock implementación framework c# entity-framework unit-testing asp.net-mvc-4 repository-pattern

c# - unit - Cómo falsificar el método DbContext.Entry en Entity Framework con patrón de repositorio



repository pattern unit of work (3)

Como quiero probar mi código unitario, he implementado el patrón de repositorio en mi aplicación MVC4. Pude hacer una interfaz de contexto, un contexto falso y usar una implementación falsa de un System.Data.Entity.DbSet siguiendo this código.

Desafortunadamente, al igual que dos carteles delante de mí ( here y here ), no logro burlarme del DbContext.Entry method . Utilizo este método para actualizar las entradas de la base de datos en mi código de la siguiente manera:

DbContext.Entry(order).State = EntityState.Modified;

No he encontrado una solución a este problema, solo personas que dicen cosas como:

"¿Y cuál es el sentido de la unidad para probar este código? Fingimos el método Find, luego falsificamos DbEntityEntry y no habrá una verdadera lógica para probar".

o para

lea this y todas las preguntas vinculadas antes de continuar. (...) Si desea probar sus repositorios, cree pruebas de integración para hablar con la base de datos real.

Eso está bien y bien, pero aún no hay respuesta a la pregunta. Leí la crítica y todavía quiero este método de Entrada, así que podré usar un contexto falso y usar objetos simulados en mi prueba unitaria. Por supuesto, también usaré pruebas de integración, pero no son tan rápidas como algunas pruebas unitarias rápidas.

El error que recibo cuando pruebo algunas implementaciones es que el Error 2 ''Project.Models.Order'' does not contain a definition for ''State'' and no extension method ''State'' accepting a first argument of type ''[whatever return type I use]'' could be found (are you missing a using directive or an assembly reference?)

Espero que alguien me ayude a crear un método DbContext.Entry falso.


Encontré la respuesta here al "agregar un nivel adicional de indirección" que obtenemos:

public void SetModified(object entity) { Entry(entity).State = EntityState.Modified; }

y use DbContext.SetModified(entity) en nuestro controlador.


Para evitar esto agregué una sobrecarga de método y agregué un atributo obsoleto para ver dónde se llamaba el método original.

public virtual void Entry<TEntity>(TEntity entity, Action<DbEntityEntry<TEntity>> action) where TEntity : class { action(base.Entry(entity)); } [Obsolete("Use overload for unit tests.")] public new DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class { return base.Entry(entity); /** or **/ throw new ApplicationException("Use overload for unit tests."); }

entonces puede DbContext.Entry(order, ent => ent.State = EntityState.Modified;


Un ejemplo de cómo implementar repositorios basados ​​en interfaz y unidad de trabajo para obtener lo que busca:

public interface IRepository<T> { T FindSingle(Expression<Func<T, Boolean>> predicate, params Expression<Func<T, object>>[] includeExpressions); void ProxyGenerationOn(); void ProxyGenerationOff(); void Detach(T entity); void Add(T newEntity); void Modify(T entity); void Attach(T entity); void Remove(T entity); void SetCurrentValues(T modifiedEntity, T origEntity); T GetById(int id); T GetById(int id, bool sealOverride); IQueryable<T> GetAll(); IQueryable<T> GetAll(bool sealOverride); IQueryable<T> GetAll(string[] EagerLoadPaths); IQueryable<T> Find(Expression<Func<T, Boolean>> predicate); } public interface IUnitOfWork : IDisposable { //repository implementations go here bool SaveChanges() }

Observe cómo el contexto se abstrae por completo. Solo debe preocuparse por ello en las implementaciones concretas.