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.