我有一种使用 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/