c# - Entity Framework 6 单元测试 (NSubstitute) - 如何测试带有子对象的对象在未请求子对象时不返回子对象

标签 c# entity-framework unit-testing unity-container nsubstitute

我有一种使用 Entity Framework 上下文获取雇主的方法(延迟加载已禁用)。有时我希望包括 Employees,有时我不想,所以我的数据访问类中有以下代码:

public Employer GetEmployer(int employerId, bool includeRelationships)
{
    Employer employer;

    if (includeRelationships)
    {
        employer = (from e in this.context.Employers.Include(e => e.Employees)
                    where e.EmployerId == employerId
                    select e).SingleOrDefault();
    }
    else
    {
        employer = this.context.Employers.SingleOrDefault(e => e.EmployerId == employerId);
    }

    return employer;
}

关于如何使用 NSubstitute 替换 EF 上下文返回的几个问题,我在我的测试项目中有这个扩展方法来连接 DbSet 调用以进行替换(特别是 NSubstitute DbSet / IQueryable<T> ):

public static IDbSet<T> Initialise<T>(this IDbSet<T> dbSet, IQueryable<T> data) where T : class
{
    dbSet.Provider.Returns(data.Provider);
    dbSet.Expression.Returns(data.Expression);
    dbSet.ElementType.Returns(data.ElementType);
    dbSet.GetEnumerator().Returns(data.GetEnumerator());
    return dbSet;
}

这随后用于初始化测试类中的一组替代雇主:

[TestInitialize]
public void TestInitialise()
{
    this.context = Substitute.For<EmployerContext>();

    this.dao = new EmployerDao(this.context);

    var employers = new List<Employer>();

    var employerWithoutEmployee = new Employer { EmployerId = 1 };

    employers.Add(employerWithoutEmployee);

    var employerWithEmployee = new Employer { EmployerId = 2 };

    var employee = new Employee { EmployeeId = 1, EmployerId = 2, Employer = employerWithEmployee };

    employerWithEmployee.Employees.Add(employee);

    employers.Add(employerWithEmployee);

    this.substituteEmployers = Substitute.For<IDbSet<Employer>>().Initialise(employers.AsQueryable());

    this.context.Employers.Returns(this.substituteEmployers);
}

所以,我现在有一个看起来像这样的测试:

[TestMethod]
public void ReturnsEmployerWithNullEmployeeWhenIncludeIsFalse()
{
    // Assemble
    var expectedEmployer = this.substituteEmployers.First(e => e.Employees.Any();

    var employerId = expectedEmployer.EmployerId;

    // Act
    var actualEmployer = this.dao.GetEmployer(employerId, false);

    var actualEmployee = actualEmployer.Employees.FirstOrDefault();

    // Assert
    Assert.AreSame(expectedEmployer, actualEmployer);
    Assert.IsNotNull(actualEmployer);
    Assert.IsNull(actualEmployee);
    this.context.Employers.ReceivedWithAnyArgs();
}

此测试在 Assert.IsNull(actualEmployee);

上失败

在实际使用中,GetEmployer 将返回一个没有 Employee child 的 Employer。

但是,因为我用 Employee 替换了 Employer(因为这是我正在测试的!)该方法返回具有 Employee 的替代。

我该如何测试?

或者,我测试不正确吗?

我是否应该使用没有雇员的雇主,因为这是上下文将返回的内容?

但这不是让测试变得毫无意义吗!?!

我在想自己在这里的圈子里......

最佳答案

我曾多次尝试使用不同的技术模拟 DbContext。但每次当我想“是的,这次它的行为就像真正的 EF!”我发现了另一个用例,当 mock 的行为不像真实的东西时。通过模拟测试确实会给你一种错误的信心。但是当相同的操作在生产中发生时,您会遇到异常和错误。

所以我的结论是停止尝试模拟 DbContext 而只是进行集成测试。设置起来有点问题,但是设置逼真的模拟需要更多时间!我在我的博客中写过如何进行无故障集成测试:http://tech.trailmax.info/2014/03/how-we-do-database-integration-tests-with-entity-framework-migrations/

现在我倾向于编写大量集成测试(用于 CRUD 的东西),这些测试实际上进入了数据库并乱七八糟。为您提供更多保证(而不是使用 db-mock)相同的操作将在生产中起作用。

不是您问题的真正答案。只是我的 .02$

关于c# - Entity Framework 6 单元测试 (NSubstitute) - 如何测试带有子对象的对象在未请求子对象时不返回子对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24328237/

相关文章:

.net - 是否有工具可以为现有模式实现 Code First 准则?

c# - 将 Entity Framework 上传到 Team Foundation(源代码管理)

c# - ConnectionString 中的可变密码

c# - 使用 C# 从 SQL 显示和保存 "time"数据类型?

c# - DbQuery.Include() 方法 : Is there a strong-typed variant?

c# - 单元测试 (C#)

javascript - 测试 AngularUI Bootstrap 模式实例 Controller

javascript - 当我运行 Mocha 测试时,我总是收到错误 : connect ECONNREFUSED

c# - c# wpf 动画结束时运行 Action

c# - 如何使用正则表达式删除一些没有特定属性的 css 属性?