使用 Entity Framework 5 的工作單元和通用儲存庫
我將 ASP.NET MVC 4 與 Entity Framework 5 一起使用。我有模型類和實體映射來將現有表映射到這些模型類。所有這些設置都很好,效果很好。
現在我想嘲笑這個。我創建了採用 DataContext 並使用通用儲存庫的工作單元。在那之後,我建構了能夠一次從許多儲存庫中獲取數據的服務,並且只需要一個 DataContext 實例。這也很好用。
**現在問題來了:**我想用模擬數據測試服務。當我創建工作單元實例時,我希望能夠插入一個模擬的 DataContext 而不是真正的 DataContext。
我試圖創建一個 IContext 介面並讓真實的和模擬的 DataContext 實現它,但遇到了 DbSet 的問題。我嘗試使用 IDbSet 並創建 FakeDbSet 但沒有成功。我還在網際網路上讀到使用 IDbSet 模擬上下文並使用 FakeDbSet 是一種不好的方法。
您知道實現這一目標的最佳方法是什麼嗎?我現在擁有的是我想保留的行為,但真的希望能夠模擬來自 DataContext 中的模型類的數據。
我知道實體框架已經帶有工作單元行為,並且您不需要在此之上添加額外的行為。但我想將它包裝在另一個跟踪所有儲存庫的類(稱為 UnitOfWork 類)中。
**編輯:**我寫了兩篇文章來解釋我使用 LINQ 和實體框架的解決方案。
<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(); }儲存庫.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; } } }範例服務.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(); }
你的
ExampleService類是期待IUnitOfWork的,這意味著你只需要另一個IUnitOfWork是 Mock 並且它的GetRepository()方法將返回一個IRepositoryMock。例如(不是真正的 Mock,而是 In-Memory 存根):
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(); }