如何防止在单元测试中自动包含导航属性

How to prevent automatic inclusion of navigation properties in unit tests

我目前正在开发一种应用商店风格 API,它具有以下实体(加上许多其他实体,但与问题无关):

我遇到了一个奇怪的问题,即 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);
        }
    }
}