简体   繁体   English

从DbContext访问Moq Mock数据两次调用时消失了吗?

[英]Accessing Moq Mock Data from DbContext disappears when called twice?

I am trying to understand a behavior that is occurring in my application. 我试图了解我的应用程序中正在发生的行为。 I have mocked out my DbContext and when I make a call get items from the dbContext.Set<T>().ToList() , the second call does not contain my mocked data. 我已经DbContext了我的DbContext ,当我进行调用时,从dbContext.Set<T>().ToList()获取项目,第二次调用不包含我的模拟数据。 I am not sure why this happens since that data should still exist. 我不确定为什么会发生这种情况,因为该数据应该仍然存在。 Please see code below: 请参见下面的代码:

SUT: SUT:

public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
    public decimal Salary { get; set; }
}

public class EmployeeDb
    : DbContext
{
    public EmployeeDb()
    {

    }

    public virtual IDbSet<Employee> Employees { get; set; }
}

UNIT TEST: 单元测试:

public class MockDatabase
{
    public Mock<EmployeeDb> SetMockData()
    {
        var mockDb = new Mock<EmployeeDb>();

        mockDb.Setup(i => i.Set<Employee>()).Returns(GetMockSet(Employees).Object);
        mockDb.SetupGet(i => i.Employees).Returns(() => GetMockSet(Employees).Object);

        return mockDb;
    }
    private List<Employee> _providers;
    private List<Employee> Employees => _providers ?? (_providers = new List<Employee>
    {
        GetEmployee(1),
        GetEmployee(2),
        GetEmployee(3),
        GetEmployee(4),
        GetEmployee(5),
    });
    private static Employee GetEmployee(int id)
    {
        return new Employee
        {
            FirstName = Faker.Name.First(),
            LastName = Faker.Name.Last(),
            Age = Faker.RandomNumber.Next(50),
            Id = id,
            Salary = Faker.RandomNumber.Next(100000)
        };
    }

    #region Hood

    public static Mock<DbSet<T>> GetMockSet<T>(IList<T> items) where T : class
    {
        var querable = items.AsQueryable();
        var mockSet = new Mock<DbSet<T>>();
        mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(querable.Provider);
        mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(querable.Expression);
        mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(querable.ElementType);
        mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(querable.GetEnumerator());
        mockSet.Setup(i => i.Add(It.IsAny<T>())).Callback(delegate (T item) {
            items.Add(item);
        });
        return mockSet;
    }

    #endregion
}


[TestClass]
public class UnitTest1
{
    private EmployeeDb _context;

    [TestInitialize]
    public void TestInitialize()
    {
        var mockDb = new MockDatabase();
        _context = mockDb.SetMockData().Object;
    }
    [TestMethod]
    public void Test_CallTwice_ReturnsEqualCount()
    {
        var emps = _context.Set<Employee>().ToList();
        var emps2 = _context.Set<Employee>().ToList();

        Assert.IsTrue(emps.Count == emps2.Count);

        // -- This works
        //var empCount = _context.Set<Employee>().Count();
        //var empCount2 = _context.Set<Employee>().Count();

        //Assert.IsTrue(empCount == empCount2);
    }
}

Is there something I am not getting about this code? 我有没有关于此代码的东西吗? Is there something Moq does with the ToList() ? Moq与ToList()吗?

ToList enumerates the set when invoked, but the enumerator is forward only, so after the first call it is already at the end. ToList在调用时枚举集合,但枚举器仅向前,因此在第一次调用之后,它已经在末尾。

When setting up the GetEnumerator use the function overload of the Returns in order to allow multiple calls other wise the same enumerator will be returned every time and you get the behavior you experienced. 设置GetEnumerator使用Returns函数的重载,以允许其他方式的多次调用,每次都会返回同一枚举数,并且您会获得所遇到的行为。

mockSet.As<IQueryable<T>>()
    .Setup(m => m.GetEnumerator())
    .Returns(() => querable.GetEnumerator()); //<-- function

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM