Unidad de trabajo y repositorio genérico con Entity Framework 5

Estoy usando ASP.NET MVC 4 con Entity Framework 5. Tengo clases modelo y mapas de entidad para asignar tablas existentes a esas clases modelo. Todo esto está bien configurado y funciona muy bien.

Ahora quiero burlarme de esto. Creé la Unidad de trabajo que toma el DataContext y usa un repositorio genérico. Luego de eso construí servicios para poder obtener datos de muchos repositorios a la vez y solo necesito tener una instancia del DataContext. Esto también funciona muy bien.

Ahora al problema: Quiero probar los servicios, con datos simulados. Cuando creo la instancia de Unidad de trabajo, quiero poder insertar un DataContext que se burla en lugar del DataContext real.

Intenté crear una interfaz IContext y dejar que el DataContext real y simulado implementara eso pero se topó con problemas con DbSet. Intenté usar IDbSet y crear un FakeDbSet pero sin éxito. También leí en Internet que burlarse del contexto con IDbSet y usar un FakeDbSet es un mal enfoque.

¿Tienes alguna idea de cuál sería la mejor manera de lograr esto? Lo que tengo ahora es el comportamiento que me gustaría mantener, pero realmente me gustaría poder burlarme de los datos de las clases del Modelo en el DataContext.

Soy consciente de que Entity Framework ya viene con el comportamiento de Unidad de trabajo y que no es necesario que agregue un comportamiento adicional. Pero quería envolver eso dentro de otra clase que hace un seguimiento de todos los repositorios (llamada clase UnitOfWork).

Editar: Escribí dos artículos explicando mi solución tanto con LINQ como con Entity Framework.

http://gaui.is/how-to-mock-the-datacontext-linq/

http://gaui.is/how-to-mock-the-datacontext-entity-framework/

Aquí está mi código:

IRepository.cs

public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Delete(T entity);
    void Update(T entity);
    T GetById(long Id);
    IEnumerable<T> All();
    IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
}

IUnitOfWork.cs

public interface IUnitOfWork : IDisposable
{
    IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
    void Save();
}

Repositorio.cs

public class Repository<T> : IRepository<T> where T : class
{
    private readonly IDbContext _context;
    private readonly IDbSet<T> _dbset;

    public Repository(IDbContext context)
    {
        _context = context;
        _dbset = context.Set<T>();
    }

    public virtual void Add(T entity)
    {
        _dbset.Add(entity);
    }

    public virtual void Delete(T entity)
    {
        var entry = _context.Entry(entity);
        entry.State = System.Data.EntityState.Deleted;
    }

    public virtual void Update(T entity)
    {
        var entry = _context.Entry(entity);
        _dbset.Attach(entity);
        entry.State = System.Data.EntityState.Modified;
    }

    public virtual T GetById(long id)
    {
        return _dbset.Find(id);
    }

    public virtual IEnumerable<T> All()
    {
        return _dbset;
    }

    public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
    {
        return _dbset.Where(predicate);
    }
}

UnitOfWork.cs

public class UnitOfWork<TContext> : IUnitOfWork where TContext : IDbContext, new()
{
    private readonly IDbContext _ctx;
    private Dictionary<Type, object> _repositories;
    private bool _disposed;

    public UnitOfWork()
    {
        _ctx = new TContext();
        _repositories = new Dictionary<Type, object>();
        _disposed = false;
    }

    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
    {
        if (_repositories.Keys.Contains(typeof(TEntity)))
            return _repositories[typeof(TEntity)] as IRepository<TEntity>;

        var repository = new Repository<TEntity>(_ctx);
        _repositories.Add(typeof(TEntity), repository);
        return repository;
    }

    public void Save()
    {
        _ctx.SaveChanges();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!this._disposed)
        {
            if (disposing)
            {
                _ctx.Dispose();
            }

            this._disposed = true;
        }
    }
}

ExampleService.cs

public class ExampleService
{
    private IRepository<Example> m_repo;

    public ExampleService(IUnitOfWork uow)
    {
        m_repo = uow.GetRepository<Example>();
    }

    public void Add(Example Example)
    {
        m_repo.Add(Example);
    }

    public IEnumerable<Example> getAll()
    {
        return m_repo.All();
    }
}

ExampleController.cs

public IEnumerable<Example> GetAll()
{
    // Create Unit Of Work object
    IUnitOfWork uow = new UnitOfWork<AppDataContext>();

    // Create Service with Unit Of Work attached to the DataContext
    ExampleService service = new ExampleService(uow);

    return service.getAll();
}

Respuestas a la pregunta(2)

Su respuesta a la pregunta