【问题标题】:Mocking DbContext in Entity Framework 6.1在实体框架 6.1 中模拟 DbContext
【发布时间】:2016-08-03 16:08:19
【问题描述】:

我找到了一些示例,这些示例(显然)显示了使用 EF 6 模拟 DbContext 的清晰工作示例,但是,它们似乎都不适合我,我也不完全确定为什么。

这是我设置模拟的单元测试代码;

var mockData = new List<User> { new User { Email = "my@email.com", Id = 1 } }.AsQueryable();

var mockSet = new Mock<DbSet<User>>();
    mockSet.As<IQueryable<User>>().Setup(m => m.Provider).Returns(mockData.Provider);
    mockSet.As<IQueryable<User>>().Setup(m => m.Expression).Returns(mockData.Expression);
    mockSet.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(mockData.ElementType);
    mockSet.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(mockData.GetEnumerator());

    var mockContext = new Mock<MyDbContext>();
    mockContext.Setup(c => c.Users).Returns(mockSet.Object);

然后调用我正在测试的服务;

var service = new UsersService(mockContext.Object);

var user = service.GetById(1);

这会引发 NullReferenceException,因为基础 DbSet 始终为 null。代码执行以下操作;

在基类中;

public IEnumerable<T> GetAll()
{
    return _dbSet.AsEnumerable();
}

在子类中;

  public User GetById(int id)
        {
            return GetAll().FirstOrDefault(x => x.Id == id);
        }

请注意,尽管关于 SO 的其他问题似乎相关,但它们不包括 EF 6。

作为参考,这是一篇 MSDN 文章,对相同的代码进行修改以使其编译。

https://msdn.microsoft.com/en-us/data/dn314429.aspx

编辑:

降低 UserService 的复杂性(它使用泛型/接口),代码现在很简单;

public User GetById(int id)
        {
            return _dbContext.Set<User>().FirstOrDefault(x => x.Id == id);
        }

如果我将其进一步更改为;

   var dbSet = _dbContext.Set<User>();
        return dbSet.FirstOrDefault(x => x.Id == id);

我可以清楚地看到 dbSet 为空。

编辑 2

根据 wablab 的建议,mock .Set 似乎解决了问题。

还要感谢 Vladyslav Kushnir 为 DbSet 的通用方法。

任何可能需要它的人的工作代码;

 private static Mock<DbSet<T>> GetDbSetMock<T>(IEnumerable<T> items = null) where T : class
        {
            if (items == null)
            {
                items = new T[0];
            }

            var dbSetMock = new Mock<DbSet<T>>();
            var q = dbSetMock.As<IQueryable<T>>();

            q.Setup(x => x.GetEnumerator()).Returns(items.GetEnumerator);

            return dbSetMock;
        }



var mockContext = new Mock<Model1>();

var users = new List<User> { new User { Email = "my@email.com", Id = 1 } };

mockContext.Setup(x => x.Set<User>()).Returns(GetDbSetMock(users).Object);

var service = new UsersService(mockContext.Object);

var user = service.GetById(1);

【问题讨论】:

  • 您是否确认您的UserService 构造函数正在分配它传递给_dbSet 字段的参数的Users 属性?
  • 如果这就是你的意思,它可以正常工作。
  • NullReferenceException 是从GetById 方法还是GetAll 方法抛出的?换句话说,是_dbSet 为null,还是_dbSet.AsEnumerable() 的结果为null? (或者其他什么都为空?)
  • 已更新,dbSet 为空。
  • 看起来您需要为返回您的mockSetSet&lt;User&gt; 方法创建一个设置。

标签: c# entity-framework unit-testing entity-framework-6 moq


【解决方案1】:

我认为您需要在 Set&lt;User&gt;() 方法上创建一个设置以返回您的模拟。

【讨论】:

  • 完美运行。谢谢
【解决方案2】:
    private Mock<DbSet<T>> GetDbSetMock<T>(IEnumerable<T> items = null) where T : class
    {
        if (items == null)
        {
            items = new T[0];
        }

        var dbSetMock = new Mock<DbSet<T>>();
        var q = dbSetMock.As<IQueryable<T>>();

        q.Setup(x => x.GetEnumerator()).Returns(items.GetEnumerator);

        return dbSetMock;
    }

这是我用来模拟 DbContext 的 DbSet 的运行良好的通用方法。这个方法的实际调用是:

var contextMock = new Mock<MyContext>();
contextMock.Setup(x => x.MyDbEntities).Returns(GetDbSetMock<MyDbEntity>().Object);

【讨论】:

  • 奇怪的是,这在我的机器上不起作用,使用此代码的 dbset 仍然为空,不过,谢谢。
  • 另外在我的上下文中我使用IDbSet 而不是DbSet 试试这个,也许它会有所帮助。
  • 可能你的代码不起作用,因为你在模拟 DbContext 的特定属性,而你试图通过Set&lt;T&gt; 访问数据时,请尝试另外模拟这个​​方法。
  • 如何在不使用.Set的情况下取出DbSet?
  • Ahyes,但我将 DbContext(基类)而不是 MyDbContext 传递给 UsersService 的构造函数。我什至直接将它更改为 MyDbContext.Users 并且它仍然为空......最后会再次选择它。
猜你喜欢
  • 2017-05-14
  • 1970-01-01
  • 1970-01-01
  • 2013-12-26
  • 2022-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-15
相关资源
最近更新 更多