简体   繁体   中英

EF6 DbSet<T> returns null in Moq

I have a typical Repository Pattern setup in my application with a DbContext (EF6):

public class MyDbContext : EFContext<MyDbContext> {

    public MyDbContext () { }

    public virtual DbSet<CartItem> Cart { get; set; }

and a repository:

public class GenericEFRepository<TEntity, TContext>
    where TEntity : class, new()
    where TContext : EFContext<TContext> {

    private readonly TContext _context;

    public GenericEFRepository(TContext context) {
        _context = context;
    }
    //...
    public virtual TEntity Insert(TEntity item) {
        return _context.Set<TEntity>().Add(item);
    }

I'm testing this with Moq 4.2 (following this tutorial ) by creating a mock context:

        // Arrange
        var mockSet = new Mock<DbSet<CartItem>>();

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

        // Act
        var service = new GenericEFRepository<CartItem, MyDbContext>(mockContext.Object);
        service.Insert(new CartItem() {
            Id = 1,
            Date = DateTime.Now,
            UserId = 1,
            Detail = string.Empty
        });

        // Assert
        mockSet.Verify(s => s.Add(It.IsAny<CartItem>()), Times.Once());

The problem is that when I reach this line:

return _context.Set<TEntity>().Add(item);

_context.Set<TEntity>() returns null. After some googling it seems in EF5 it was necessary to return IDbSet<T> for Moq to mock the set, but not with EF6. Is this not the case, or am I missing something?

Add a setup for the Set<T>() method:

mockContext.Setup(c => c.Set<CartItem>()).Returns(mockSet.Object);

Even though on the real EFContext the property Cart and Set<CartItem>() refer to the same object, the mock of the context doesn't know that, so you need to tell it explicitly what to return.

Since it was a loose mock, the call to a method that hasn't been setup returns the default value, which in this case is null . Strict mocks are nice in helping find this error, but also have maintenance costs that other folks don't want to deal with .

This solution is still correct for me at the end of 2020 with EntitiFramework Core. Not so easy to understand how to mock objects/datasets, I'm starting right now to implement some Integration tests using in-memory DB with mocked data. I saw my method worked correctly for example if I do:

await _dbcontext.MyEntirySet.ToListAsync();

but failed when using equivalend in a generic Repository

_dbcontext.Set<TEntity>  : this return a null dataset.

I can confirm mocking Set fix the problem even with EntityFramework Core.

 _dbContextMock.Setup(c => c.Set<MyEntityType>()).Returns(mock.Object);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM