Ответ 1
Итак, некоторые выводы. Я думал, что напишу это на случай, если он будет полезен кому-то другому, пытающемуся использовать / unit test EF, Windsor и MVC вместе.
Прежде всего, поскольку DbContext реализует как шаблоны репозитория, так и единицы работы, вам нужно взглянуть на то, будут ли выполняться эти реализации или вам нужно создать свои собственные.
Я решил создать свой собственный репозиторий, следуя шаблону DDD: по одному для каждого заполнителя. Причины: инкапсулировать код запроса, чтобы он не просочился в уровень приложения и не мог более легко насмехаться при тестировании контроллеров приложений. Я создал общий репозиторий на основе IRepository<TEntity>
. Есть много примеров. Я нашел это хорошим: http://architects.dzone.com/articles/implementing-repository
С другой стороны, я решил отказаться от службы IUnitOfWork, выбрав вместо нее реализацию по умолчанию. Тем не менее, я создал абстракцию IDbContext (не знаю, почему Microsoft не делала этого сама), поэтому я мог издеваться над DbContext при тестировании сервисов репозитория.
Я дал IDbContext только члены DbContext, которые я хотел использовать в репозитории. Итак:
public interface IDbContext: IDisposable
{
Database Database { get; }
DbEntityEntry Entry(object entity);
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
Затем я создал средство и установщик Windsor для своих служб IDbContext и IRepository:
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() для возврата IDbSet, а не DbSet:
public partial class MyEntities : IDbContext
{
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
}
При наличии всего этого (и регистрации ControllerFactory, показанной в документах Windsor) становится тривиальным, чтобы заставить 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);