2013-05-23 11 views
27

私はEntity Framework 5でASP.NET MVC 4を使用しています。既存のテーブルをモデルクラスにマップするためのモデルクラスとEntityマップがあります。すべてこれはうまく動作し、うまく動作します。Entity Framework 5を使用した作業単位と汎用リポジトリ

今私はこれを嘲笑したい。 DataContextを使用し、汎用リポジトリを使用する作業単位を作成しました。その上で、私は一度に多くのリポジトリからデータを取得し、DataContextの1つのインスタンスを必要とするだけのサービスを構築しました。これも素晴らしいです。

問題が発生しました:私は模擬データを使ってサービスをテストしたいと思います。 Unit Of Workインスタンスを作成するときに、実際のDataContextの代わりにmockedされたDataContextを挿入できるようにします。

私はIContextインターフェイスを作成しようとしましたが、実際のDataContextはそれを実装しましたが、DbSetの問題に遭遇しました。 IDbSetを使ってFakeDbSetを作成しようとしましたが、成功しませんでした。私はまた、IDbSetでコンテキストを嘲笑し、FakeDbSetを使うことは悪いアプローチであることをインターネット上で読んでいます。

これを達成するための最良の方法は何ですか?私が今保有しているのは、保持したい動作ですが、DataContextのModelクラスからデータをモックすることが本当に好きです。

私は、Entity Frameworkに既にUnit Of Workの動作が付属していることを認識しており、その上に特別な動作を追加する必要はありません。しかし、私はすべてのリポジトリ(UnitOfWorkクラスと呼ばれる)を追跡する別のクラスの内部を包み込みたいと思っていました。

編集:私はLINQとEntity Frameworkの両方で私のソリューションを説明する2つの記事を書いています。

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

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

ここに私のコードは次のとおりです。

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

私はまた、あなたが言及したのと同じ問題を抱えています。しかし、IDbContextとIDbContextを実装する具体的なクラスのコードを投稿できますか?これは私をたくさん助けます。前もって感謝します。 – NoobDeveloper

+0

@Nexus [http://gaui.is/how-to-mock-the-datacontext-entity-framework/](http://gaui.is/how-to-mock-the-datacontextentity-framework/ ) – Gaui

+1

@Gauiコントローラの代わりに 'ExampleService'クラスの中に' UnitOfWork'インスタンスを作成するほうがよいでしょうか?そうすれば、あなたのコントローラは必要な 'DbContext'を知る必要がなくなり、それをサービスに残します。 – GFoley83

答えて

10

あなたExampleServiceクラスは、あなただけのIRepositoryモックを返しますモックとそのGetRepository()方法で別のIUnitOfWorkを必要とすることを意味し、IUnitOfWorkを期待しています。

例えば

(ない本当にモックなく、インメモリスタブ):次に

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

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

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

優秀、魅力のように動作します!私はIDbSetとFakeDbSetを使って偽のコンテキストを作成するよりも、これが好きです。それは間違っているようです。これはありがとうございます! – Gaui

+0

これは、DBSetsを嘲笑するのではなく、きちんとしたきれいに見えます。共有のおかげで、私も同じようにさまよっていました。 –

関連する問題