Moq 设置添加相同 "Filter" 而不是覆盖

Moq Setup Adding With Same "Filter" instead of overwriting

我正在尝试在 Moq 中模拟 DbSet<>,我可以在其中添加到 DbSet<> 中的实体列表。换句话说,一个可变的 DbSet<>.

我为此编写了一些扩展方法,但已将问题提炼成一个测试。

认为 在 Moq 中,如果您使用相同的参数设置相同的调用(过滤器),设置是否被替换?

但是,下面的单元测试显示它已添加?

见'below throws "Expected collection to contain 1 item(s), but found 2."'

        [Fact]
        public void Add2Test()
        {
            var contextMock = new Mock<IDbContext>();
            List<MyEntity> data = new List<MyEntity>(){new MyEntity()};
            var queryable = data.AsQueryable();
            var mockDbSet = new Mock<DbSet<MyEntity>>();
            mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.Provider).Returns(queryable.Provider);
            mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.Expression).Returns(queryable.Expression);
            mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
            mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
            contextMock.Setups.Where(s => s.Expression.ReturnType == typeof(DbSet<MyEntity>)).Should().HaveCount(0);
            contextMock.Setup(x => x.Set<MyEntity>()).Returns(mockDbSet.Object);
            contextMock.Setups.Where(s => s.Expression.ReturnType == typeof(DbSet<MyEntity>)).Should().HaveCount(1);
            // let's do it again
            data = new List<MyEntity>() { new MyEntity() };
            queryable = data.AsQueryable();
            mockDbSet = new Mock<DbSet<MyEntity>>();
            mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.Provider).Returns(queryable.Provider);
            mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.Expression).Returns(queryable.Expression);
            mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
            mockDbSet.As<IQueryable<MyEntity>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
            contextMock.Setups.Where(s => s.Expression.ReturnType == typeof(DbSet<MyEntity>)).Should().HaveCount(1);
            contextMock.Setup(x => x.Set<MyEntity>()).Returns(mockDbSet.Object);
            // below throws "Expected collection to contain 1 item(s), but found 2."
            contextMock.Setups.Where(s => s.Expression.ReturnType == typeof(DbSet<MyEntity>)).Should().HaveCount(1);
        }

根据我对 EntityFrameworkCore.Testing, MemoryCache.Testing 等编写库的观察,Moq 没有 replace/override 相同的现有设置。

虽然这是一个 Moq 实现细节,但目前如果您多次设置相同的表达式,将使用最后添加的设置。

void Main()
{
    var mock = new Mock<IFoo>();
    mock.Setup(x => x.Bar()).Returns("A");
    mock.Setup(x => x.Bar()).Returns("B");
    var mocked = mock.Object;
    Console.WriteLine(mocked.Bar());
    Console.WriteLine(mock.Setups.Select(x => x.ToString()));
}

public interface IFoo
{
    public string Bar();
}