如何使用存储库模式伪造Entity Framework中的DbContext.Entry方法

时间:2013-12-09 13:33:17

标签: c# entity-framework unit-testing asp.net-mvc-4 repository-pattern

因为我想对我的代码进行单元测试,所以我在MVC4应用程序中实现了存储库模式。我设法创建了一个Context Interface,一个假的Context,并通过跟随System.Data.Entity.DbSet代码使用this的假实现。

不幸的是,就像我面前的两张海报(herehere)一样,我无法模仿DbContext.Entry method。我使用此方法更新代码中的数据库条目,如下所示:

DbContext.Entry(order).State = EntityState.Modified;

我还没有找到解决这个问题的方法,只有那些人说的话:

  

“这个代码的单元测试有什么意义?你伪造了Find   方法,那么你伪造DbEntityEntry并没有真正的逻辑   试验“。

  在继续之前,请先阅读this以及所有相关问题。 (...)如果您想测试您的存储库,请创建与真实数据库对话的集成测试。

这一切都很好,但仍然没有回答这个问题。我阅读了批评,我仍然想要这个Entry方法,所以我将能够使用假上下文并在我的单元测试中使用模拟对象。当然我也会使用集成测试,但它们并不像某些快速单元测试那么快。

我尝试某些实现时收到的错误是Error 2 'Project.Models.Order' does not contain a definition for 'State' and no extension method 'State' accepting a first argument of type '[whatever return type I use]' could be found (are you missing a using directive or an assembly reference?)

我希望有人可以帮我制作一个虚假的DbContext.Entry方法。

4 个答案:

答案 0 :(得分:36)

通过“添加更多级别的间接”找到答案here

public void SetModified(object entity)
{
    Entry(entity).State = EntityState.Modified;
}

并在我们的控制器中使用DbContext.SetModified(entity)

答案 1 :(得分:5)

为了解决这个问题,我添加了一个方法重载,并添加了一个过时的属性来查看原始方法的调用位置。

If Not myRecipients.ResolveAll Then

然后你可以 public virtual void Entry<TEntity>(TEntity entity, Action<DbEntityEntry<TEntity>> action) where TEntity : class { action(base.Entry(entity)); } [Obsolete("Use overload for unit tests.")] public new DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class { return base.Entry(entity); /** or **/ throw new ApplicationException("Use overload for unit tests."); }

答案 2 :(得分:2)

如何实现基于接口的存储库和工作单元以获取您所需的内容的示例:

public interface IRepository<T>
    {
        T FindSingle(Expression<Func<T, Boolean>> predicate, params Expression<Func<T, object>>[] includeExpressions);
        void ProxyGenerationOn();
        void ProxyGenerationOff();
        void Detach(T entity);
        void Add(T newEntity);
        void Modify(T entity);
        void Attach(T entity);
        void Remove(T entity);
        void SetCurrentValues(T modifiedEntity, T origEntity);
        T GetById(int id);
        T GetById(int id, bool sealOverride);
        IQueryable<T> GetAll();
        IQueryable<T> GetAll(bool sealOverride);
        IQueryable<T> GetAll(string[] EagerLoadPaths);
        IQueryable<T> Find(Expression<Func<T, Boolean>> predicate);
    }



public interface IUnitOfWork : IDisposable
    {
       //repository implementations go here
       bool SaveChanges()
     }

注意上下文是如何被完全抽象掉的。您只需要在具体实现中担心它。

答案 3 :(得分:2)

您可以使用DbContext.Update(entity)。就我而言,它可以正常工作,因为我嘲笑了DbContext

_dbContext.Update(entity);