Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 312
Stephen Collins Avatar asked Aug 29 '14 13:08

Stephen Collins


1 Answers

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.

like image 110
Patrick Quirk Avatar answered Sep 28 '22 13:09

Patrick Quirk