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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With