如何防止在单元测试中自动包含导航属性
How to prevent automatic inclusion of navigation properties in unit tests
我目前正在开发一种应用商店风格 API,它具有以下实体(加上许多其他实体,但与问题无关):
- App(与 AppRevision 的一对多关系 - 包含 IEnumerable 属性)
- AppRevision
- 安装
我遇到了一个奇怪的问题,即 EF 在单元测试中的行为与实际 运行 设置 API 时的行为不同,因为单元测试时会自动包含导航属性。
从我的命令处理程序中获取以下代码片段:
App app = await this.context.Apps
.Include(a => a.Installations)
.FirstOrDefaultAsync(a => a.Id == command.AppId);
if (app != null) {
// Code omitted for brevity
}
当 运行 宁 API 时,如果我在这段代码 运行 之后检查 app
,App 实体上的 AppRevisions 集合是空的,因为你会期望因为我没有明确告诉 EF .Include(a => a.AppRevisions)
- API 然后在稍后尝试处理需要此数据的代码时抛出异常。
现在查看同一处理程序的以下单元测试:
[Fact]
public async void Handle_ShouldAddInstallationRecord_WhenDataIsValid()
{
Guid testGuid = Guid.NewGuid();
CreateInstallationCommand command = new CreateInstallationCommand(testGuid, "ABC", "abc@abc.com", null);
using (TestContext context = new TestContextFactory().CreateTestContext())
{
context.Apps.Add(new App() { Id = testGuid });
context.AppRevisions.Add(new AppRevision() { Id = Guid.NewGuid(), AppId = testGuid, Status = AppRevisionStatus.Approved, IsListed = true });
await context.SaveChangesAsync();
CreateInstallationCommandHandler handler = new CreateInstallationCommandHandler(context);
CommandResult result = await handler.Handle(command, new CancellationToken());
Assert.True(result);
Assert.Single(context.Installations);
}
}
如果我逐步完成此测试,当我到达处理程序并检查 app
变量时,AppRevisions 集合已自动填充。结果,测试通过了,因为需要填充 AppRevisions 集合的代码可以执行。
期望这个测试实际上应该失败,因为我没有告诉 EF 在查询中包含这些实体。
我正在内存数据库中使用 Sqlite 为我的单元测试和 运行ning .NET Core 2.2
创建数据库上下文
我原本以为这与changetracker有关。虽然禁用它确实解决了上面报告的直接问题,但它会产生大量其他问题,因此不是一个可行的解决方案(并且可能无论如何都不是正确的解决方案)
非常感谢收到的任何建议
对于以后遇到此 post 的任何人,解决方案是根据对原始问题的评论,使用单独的上下文来播种测试数据并在稍后的测试中获取数据:
[Fact]
public async void Handle_ShouldAddInstallationRecord_WhenDataIsValid()
{
Guid testGuid = Guid.NewGuid();
CreateInstallationCommand command = new CreateInstallationCommand(testGuid, "ABC", "abc@abc.com", null);
using (TestContextFactory contextFactory = new TestContextFactory())
{
using (TestContext seedContext = contextFactory.CreateTestContext())
{
seedContext.Apps.Add(new App() { Id = testGuid });
seedContext.AppRevisions.Add(new AppRevision() { Id = Guid.NewGuid(), AppId = testGuid, Status = AppRevisionStatus.Approved, IsListed = true });
await seedContext.SaveChangesAsync();
}
using (TestContext getContext = contextFactory.CreateTestContext())
{
CreateInstallationCommandHandler handler = new CreateInstallationCommandHandler(getContext);
CommandResult result = await handler.Handle(command, new CancellationToken());
Assert.True(result);
Assert.Single(getContext.Installations);
}
}
}
我目前正在开发一种应用商店风格 API,它具有以下实体(加上许多其他实体,但与问题无关):
- App(与 AppRevision 的一对多关系 - 包含 IEnumerable 属性)
- AppRevision
- 安装
我遇到了一个奇怪的问题,即 EF 在单元测试中的行为与实际 运行 设置 API 时的行为不同,因为单元测试时会自动包含导航属性。
从我的命令处理程序中获取以下代码片段:
App app = await this.context.Apps
.Include(a => a.Installations)
.FirstOrDefaultAsync(a => a.Id == command.AppId);
if (app != null) {
// Code omitted for brevity
}
当 运行 宁 API 时,如果我在这段代码 运行 之后检查 app
,App 实体上的 AppRevisions 集合是空的,因为你会期望因为我没有明确告诉 EF .Include(a => a.AppRevisions)
- API 然后在稍后尝试处理需要此数据的代码时抛出异常。
现在查看同一处理程序的以下单元测试:
[Fact]
public async void Handle_ShouldAddInstallationRecord_WhenDataIsValid()
{
Guid testGuid = Guid.NewGuid();
CreateInstallationCommand command = new CreateInstallationCommand(testGuid, "ABC", "abc@abc.com", null);
using (TestContext context = new TestContextFactory().CreateTestContext())
{
context.Apps.Add(new App() { Id = testGuid });
context.AppRevisions.Add(new AppRevision() { Id = Guid.NewGuid(), AppId = testGuid, Status = AppRevisionStatus.Approved, IsListed = true });
await context.SaveChangesAsync();
CreateInstallationCommandHandler handler = new CreateInstallationCommandHandler(context);
CommandResult result = await handler.Handle(command, new CancellationToken());
Assert.True(result);
Assert.Single(context.Installations);
}
}
如果我逐步完成此测试,当我到达处理程序并检查 app
变量时,AppRevisions 集合已自动填充。结果,测试通过了,因为需要填充 AppRevisions 集合的代码可以执行。
期望这个测试实际上应该失败,因为我没有告诉 EF 在查询中包含这些实体。
我正在内存数据库中使用 Sqlite 为我的单元测试和 运行ning .NET Core 2.2
创建数据库上下文我原本以为这与changetracker有关。虽然禁用它确实解决了上面报告的直接问题,但它会产生大量其他问题,因此不是一个可行的解决方案(并且可能无论如何都不是正确的解决方案)
非常感谢收到的任何建议
对于以后遇到此 post 的任何人,解决方案是根据对原始问题的评论,使用单独的上下文来播种测试数据并在稍后的测试中获取数据:
[Fact]
public async void Handle_ShouldAddInstallationRecord_WhenDataIsValid()
{
Guid testGuid = Guid.NewGuid();
CreateInstallationCommand command = new CreateInstallationCommand(testGuid, "ABC", "abc@abc.com", null);
using (TestContextFactory contextFactory = new TestContextFactory())
{
using (TestContext seedContext = contextFactory.CreateTestContext())
{
seedContext.Apps.Add(new App() { Id = testGuid });
seedContext.AppRevisions.Add(new AppRevision() { Id = Guid.NewGuid(), AppId = testGuid, Status = AppRevisionStatus.Approved, IsListed = true });
await seedContext.SaveChangesAsync();
}
using (TestContext getContext = contextFactory.CreateTestContext())
{
CreateInstallationCommandHandler handler = new CreateInstallationCommandHandler(getContext);
CommandResult result = await handler.Handle(command, new CancellationToken());
Assert.True(result);
Assert.Single(getContext.Installations);
}
}
}