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:Even though on the real
EFContext
the propertyCart
andSet<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.