webentwicklung-frage-antwort-db.com.de

Arbeitseinheit und generisches Repository mit Entity Framework 5

Ich verwende ASP.NET MVC 4 mit Entity Framework 5. Ich habe Modellklassen und Entitätskarten, um vorhandene Tabellen diesen Modellklassen zuzuordnen. Das alles ist gut eingerichtet und funktioniert großartig.

Jetzt möchte ich das verspotten. Ich habe Unit Of Work erstellt, die den DataContext verwendet und ein generisches Repository verwendet. Danach baute ich Services auf, um Daten aus vielen Repositorys gleichzeitig abzurufen und nur eine Instanz von DataContext zu benötigen. Das funktioniert auch super.

Nun zum Problem: Ich möchte die Dienste mit Mock-Daten testen. Beim Erstellen der Unit Of Work-Instanz möchte ich in der Lage sein, einen DataContext einzufügen, der statt des echten DataContext verspottet wird.

Ich habe versucht, eine IContext-Schnittstelle zu erstellen, und ließ den realen und verspotteten DataContext implementieren, der jedoch Probleme mit DbSet hatte. Ich habe versucht, IDbSet zu verwenden und ein FakeDbSet zu erstellen, jedoch ohne Erfolg. Ich habe auch im Internet gelesen, dass das Verspotten des Kontextes mit IDbSet und das Verwenden eines FakeDbSet ein schlechter Ansatz ist.

Haben Sie eine Idee, wie Sie dies am besten erreichen können? Was ich jetzt habe, ist das Verhalten, das ich behalten möchte, aber ich möchte wirklich gerne die Daten aus den Model-Klassen im DataContext verspotten.

Ich bin mir bewusst, dass Entity Framework bereits mit dem Verhalten von Unit Of Work einhergeht und dass Sie dazu kein zusätzliches Verhalten hinzufügen müssen. Aber ich wollte das in eine andere Klasse packen, die alle Repositorys (UnitOfWork-Klasse) aufzeichnet.

Edit: Ich habe zwei Artikel geschrieben, in denen ich meine Lösung sowohl mit LINQ als auch mit Entity Framework erläuterte.

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

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

Hier ist mein Code:

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();
}

Repository.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();
}
27
Gaui

Ihre ExampleService-Klasse erwartet IUnitOfWork, dh Sie benötigen nur eine andere IUnitOfWork, die ein Mock ist, und ihre GetRepository()-Methode gibt ein IRepository-Mock zurück.

Zum Beispiel (nicht wirklich ein Mock-, sondern In-Memory-Stub):

  public InMemoryRepository<T> : IRepository<T> where T : class
  {
        ........
  }

  public InMemoryUnitOfWork : IUnitOfWork
  {
       public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
       {
            return new InMemoryRepository<TEntity>();
       }
  }

Dann:

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

    // Create Service with Unit Of Work
    ExampleService service = new ExampleService(uow);

    return service.getAll();
}
10
haim770
0