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

问题描述 投票:40回答:4

因为我想对我的代码进行单元测试,我在我的MVC4应用程序中实现了存储库模式。我设法做了一个上下文接口,一个假的上下文,并使用了一个假的实现的 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方法。

c# entity-framework unit-testing asp.net-mvc-4 repository-pattern
4个回答
38
投票

找到了答案 此处 通过 "增加额外的间接层次",我们得到。

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

并使用 DbContext.SetModified(entity) 的控制器中。


5
投票

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

    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;


2
投票

一个如何实现基于Interface的资源库和工作单元的例子,以获得你想要的东西。

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

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


2
投票

你可以使用 DbContext.Update(entity). 在我的例子中,它工作得很好,因为我嘲笑了 DbContext.

_dbContext.Update(entity);
© www.soinside.com 2019 - 2024. All rights reserved.