だから、いくつかの結論。EF、Windsor、MVCを一緒に使用/ユニットテストしようとしている他の人に役立つ場合に備えて、これを書き留めると思いました。
まず、DbContextはリポジトリと作業単位の両方のパターンを実装しているため、これらの実装が機能するかどうか、または独自の実装を作成する必要があるかどうかを確認する必要があります。
DDDパターンに従って、独自のリポジトリを作成することを選択しました。集約ルートごとに1つです。理由:クエリコードをカプセル化するため、アプリケーションレイヤーにリークするのを防ぐため、およびアプリケーションコントローラーをテストするときにモックを作成しやすくするため。に基づいて汎用リポジトリを作成しましたIRepository<TEntity>
。そこにはたくさんの例があります。私はこれが良いものだと思いました:http://architects.dzone.com/articles/implementing-repository
一方、私はIUnitOfWorkサービスを削除し、代わりにデフォルトの実装を選択することにしました。ただし、リポジトリサービスをテストするときにDbContextをモックできるように、IDbContext抽象化を作成しました(Microsoftがこれを自分で行わなかった理由はわかりません)。
IDbContextには、リポジトリで使用したいDbContextのメンバーのみを指定しました。それで:
public interface IDbContext: IDisposable
{
Database Database { get; }
DbEntityEntry Entry(object entity);
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
次に、IDbContextおよびIRepositoryサービス用のWindsorファシリティとインストーラを作成しました。
public class EntityFrameworkFacility: AbstractFacility
{
protected override void Init()
{
Kernel.Register(Component.For<IDbContext>()
.ImplementedBy<MyEntities>()
.LifestylePerWebRequest(),
Component.For(typeof(IRepository<>))
.ImplementedBy(typeof(Repository<>))
.LifestylePerWebRequest());
}
}
public class PersistenceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<EntityFrameworkFacility>();
}
}
最後の部分は、Entity Frameworkコンテキストクラスを拡張してIDbContextを実装し、Set()メソッドをシャドウイングしてDbSetではなくIDbSetを返すことでした。
public partial class MyEntities : IDbContext
{
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
}
これらすべてが整ったら(およびWindsorドキュメントに示されているControllerFactory登録)、必要に応じて、WindsorにIRepositoryオブジェクト(またはIDbContext)をコントローラーコンストラクターに挿入させるのは簡単です。
public ControllerBase(IRepository<Contact> repo)
{
_repo = repo;
}
リポジトリ単体テストでは、実際のリポジトリインスタンスをモックIDbContextでバックアップできます。
mocks = new MockRepository();
context = mocks.StrictMock<IDbContext>();
repo = new Repository<Contact>(context);
コントローラの単体テストでは、モックリポジトリを使用できます。
mocks = new MockRepository();
repo = mocks.StrictMock<IRepository<Contact>>();
ContactController controller = new ContactController(repo);