Mocking DbContext in Entity Framework 6.1

早过忘川 提交于 2019-12-25 09:24:24

问题


I have found a number of examples that show (apparently) a clear working example of mocking DbContext with EF 6, however, none of them seem to work for me and I am not entirely sure why.

This is my unit test code that sets up the mock;

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);

and then the call to the service I am testing;

var service = new UsersService(mockContext.Object);

var user = service.GetById(1);

This throws a NullReferenceException as the underlying DbSet is always null. The code does the following;

In BaseClass;

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

In subclass;

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

Please note that although there are other questions on SO that appear to be related, they do not cover EF 6.

For reference, this is an MSDN article that the same code with a modification to make it compile.

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

EDIT:

Reducing the complexity of the UserService (its uses generics/interfaces), the code is now simply;

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

If I change this further to;

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

I can clearly see that dbSet is null.

Edit 2

As per the suggestion from wablab, it appears that mock .Set resolved the problem.

Credit also to Vladyslav Kushnir for the Generic method for DbSet.

Working code for this for anyone that might need it;

 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);

回答1:


I think you need to create a setup on the Set<User>() method to return your mock.




回答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;
    }

Here is my pretty well working generic method I'm using for mocking DbSet of DbContext. The actuall call of this method is:

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


来源:https://stackoverflow.com/questions/38748666/mocking-dbcontext-in-entity-framework-6-1

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!