使用Moq模拟包含导航属性的EntityFramework查询

时间:2018-03-06 13:27:40

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

我正在尝试为我们的存储库/工作单元框架设置单元和集成测试。模拟查询工作正常,直到引入导航属性。以下工作正常:

var customers = (from cus in Customers.GetAll()
                    join acm in AccountManagers.GetAll() on cus.INS_Id equals acm.INS_Id
                    join the in Employees.GetAll() on acm.THE_Id equals the.THE_Id

                    select new CustomerModel()
                    {
                        Id = cus.INS_Id,
                        Name = cus.INS_Name,
                        OrganizationNumber = cus.INS_OrgNo,
                        PostalAddress = cus.INS_PostalAddress1,
                        PostalCity = cus.INS_PostalCity,
                        ...

但是,在这样的选择中添加一行不起作用:

var customers = (from cus in Customers.GetAll()
                    join acm in AccountManagers.GetAll() on cus.INS_Id equals acm.INS_Id
                    join the in Employees.GetAll() on acm.THE_Id equals the.THE_Id

                    select new CustomerModel()
                    {
                        Id = cus.INS_Id,
                        Name = cus.INS_Name,
                        OrganizationNumber = cus.INS_OrgNo,
                        PostalAddress = cus.INS_PostalAddress1,
                        PostalCity = cus.INS_PostalCity,
                        Brokered = cus.InsuredBrokers.Any(),
                        ...

原因是cus.InsuredBrokers是导航属性,而Moq不知道如何处理它。

我已经设置了这样的测试:

// Sets up a new Mock DbSet, given a list of inmemory data
private Mock<DbSet<T>> SetupSet<T>(IQueryable<T> data) where T : class
{
    var mockSet = new Mock<DbSet<T>>();
    mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(data.Provider);
    mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression);
    mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType);
    mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

    return mockSet;
}

// Sets up a new Mock DbContext with a given Mock DbSet of data
private Mock<PrositContext> SetupContext<T>(Mock<DbSet<T>> set) where T : class
{
    var mockContext = new Mock<PrositContext>();
    mockContext.Setup(m => m.Set<T>()).Returns(set.Object);

    return mockContext;
}

// Adds a given Mock DbSet of data to an existing Mock DbContext
private Mock<PrositContext> SetupContext<T>(Mock<DbSet<T>> set, Mock<PrositContext> existingContext) where T : class
{
    existingContext.Setup(m => m.Set<T>()).Returns(set.Object);

    return existingContext;
}

// Sets up a new Mock DbContext given a list of inmemory data
private Mock<PrositContext> SetupContext<T>(IQueryable<T> data) where T : class
{
    var mockSet = SetupSet(data);
    return SetupContext(mockSet);
}

// Adds to an existing Mock DbContext a list of inmemory data
private Mock<PrositContext> SetupContext<T>(IQueryable<T> data, Mock<PrositContext> existingContext) where T : class
{
    var mockSet = SetupSet(data);
    return SetupContext(mockSet, existingContext);
}

[TestMethod]
public void TestGetCustomerName()
{
    // ARRANGE

    // Read the data from a .csv file
    var customerData = new CsvCustomerRepository(null).GetAll();
    var accountManagerData = new CsvAccountManagerRepository(null).GetAll();
    var employeeData = new CsvTHEmployeeRepository(null).GetAll();
    var nrsData = new CsvNordicRiskSolutionsRepository(null).GetAll();
    var inbData = new CsvInsuredBrokersRepository(null).GetAll();
    var gsiData = new CsvGeneralSystemInfoRepository(null).GetAll();

    // Setup the mock context with all the data from the .csv
    var mockContext = SetupContext(customerData);
    SetupContext(accountManagerData, mockContext);
    SetupContext(employeeData, mockContext);
    SetupContext(nrsData, mockContext);
    SetupContext(inbData, mockContext);
    SetupContext(gsiData, mockContext);

    var customerFacade = new CustomerFacade(mockContext.Object);

    // ACT

    var customers = customerFacade.GetByNameMOCKFORTESTING("Bos");

    // ASSERT

    //Assert.AreEqual(...);
}

public IEnumerable<ICustomerModel> GetByNameMOCKFORTESTING(string name)
{
    var customers = (from cus in Customers.GetAll()
                        join acm in AccountManagers.GetAll() on cus.INS_Id equals acm.INS_Id
                        join the in Employees.GetAll() on acm.THE_Id equals the.THE_Id
                        where cus.INS_Name.Contains(name)
                        select new CustomerModel()
                        {
                            Id = cus.INS_Id,
                            Name = cus.INS_Name,
                            OrganizationNumber = cus.INS_OrgNo,
                            PostalAddress = cus.INS_PostalAddress1,
                            PostalCity = cus.INS_PostalCity,
                            Brokered = cus.InsuredBrokers.Any(),
                            CustomerResponsible = new THEmployeeModel()
                            {
                                FirstName = the.THE_FirstName,
                                LastName = the.THE_LastName,
                                PhoneNumber = null
                            },
                            RiskClass = cus.INS_RiskKlass,
                        }).Take(300).ToList();

    return customers;
}

我需要做些什么来模拟cus.InsuredBrokers?我发现的示例,视频和教程没有涉及导航属性的主题,即使它们是常用的......

1 个答案:

答案 0 :(得分:0)

模拟实体框架非常困难。即使您成功模拟了导航属性,那么使用延迟加载的序列或代码也是如此。你最终会为你的测试编写大量的模拟设置。

我们遇到了类似的问题,并使用Effort解决了这个问题,enter image description here是内存数据库的EF提供程序。您可以为测试设置数据库,只需要模拟工作单元的创建。