EF6 DbSet <t>在Moq中返回null </t>

时间:2014-08-29 13:32:29

标签: c# entity-framework unit-testing moq entity-framework-6

我的应用程序中使用DbContext(EF6)设置了典型的存储库模式:

public class MyDbContext : EFContext<MyDbContext> {

    public MyDbContext () { }

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

和存储库:

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);
    }

我正在使用Moq 4.2(this tutorial之后)通过创建模拟上下文来测试它:

        // 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());

问题在于,当我到达这一行时:

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

_context.Set<TEntity>()返回null。经过一些谷歌搜索似乎在EF5中,有必要返回IDbSet<T>为Moq模拟集合,但不是EF6。是不是这样,或者我错过了什么?

2 个答案:

答案 0 :(得分:15)

Set<T>()方法添加设置:

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

即使真实的EFContext属性CartSet<CartItem>()引用同一个对象,上下文的 mock 也不知道,所以你需要明确告诉它要返回什么。

由于它是一个松散的模拟,因此对尚未设置的方法的调用将返回默认值,在本例中为null。严格的模拟很有助于发现此错误,但也have maintenance costs that other folks don't want to deal with

答案 1 :(得分:0)

对于2020年底,使用EntitiFramework Core来说,此解决方案对我仍然正确。 要理解如何模拟对象/数据集不是那么容易,我现在开始使用带有模拟数据的内存数据库来实现一些集成测试。 我看到自己的方法可以正常工作,例如:

await _dbcontext.MyEntirySet.ToListAsync();

但在通用存储库中使用等价时失败

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

即使使用EntityFramework Core,我也可以确认模拟Set可以解决问题。

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