如何在具有存储库模式的实体框架中伪造DbContext.Entry方法

本文关键字:框架 实体 伪造 DbContext 方法 Entry 模式 存储 | 更新日期: 2024-08-10 00:31:55

因为我想对代码进行单元测试,所以我在MVC4应用程序中实现了存储库模式。我按照这段代码制作了一个Context接口,一个假的Context,并使用了一个假的System.Data.Entity.DbSet实现。

不幸的是,就像我面前的两张海报一样(这里和这里),我没能嘲笑DbContext.Entry method。我使用这种方法更新代码中的数据库条目,如下所示:

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

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

"单元测试这个代码有什么意义?你伪造了Find方法,则您伪造DbEntityEntry,并且将没有真正的逻辑测验"

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

这一切都很好,但仍然没有答案。我读了评论,我仍然想要这个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方法。

如何在具有存储库模式的实体框架中伪造DbContext.Entry方法

通过"增加附加水平的间接性";我们得到:

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

并在控制器中使用CCD_ 4。mockContext.Setup(c=>c.SetModified(It.IsAny()));

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

    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.");
    }

则可以DbContext.Entry(order, ent => ent.State = EntityState.Modified;

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

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()
     }

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

您可以使用DbContext.Update(entity)。就我而言,它运行良好,因为我嘲笑了DbContext

_dbContext.Update(entity);