如何将实体框架核心数据库作为 InMemory 进行测试,并具有大量行的插入功能



在我们的一个项目中,我们有一个包含大量表和数千行的数据库。对于我们的集成测试,我们希望我们的测试针对固定的数据库状态(例如 5000 行)运行,以便测试具有确定性并始终返回相同的结果。

我们之前使用过一个小的实体框架核心 InMemoryDatabases,我们在其中添加了 20 行,如下所示:

private DbContextOptions<OurDataContext> GetInMemoryDbContextOptions()
{
var options = new DbContextOptionsBuilder<OurDataContext>()
.UseInMemoryDatabase(databaseName: "foo")
.Options;
using (var context = new OurDataContext(options))
{
context.OurTable.Add(new OurTable(){...});
// ...
context.SaveChanges();
}
return options;
}

但是,在我们的新案例中,对于应该从生产数据库派生的这么多行,这是不可行的。我们需要一种将真实数据同步到内存数据库的好方法。如何做到这一点?

理想情况下,我们会使用 SQL Management Studio 将生产数据库的相关部分导出到 SQL 脚本中,并在 Git 中跟踪此 SQL 导出,作为测试代码的一部分。据我们所知,由于我们无法针对它运行 SQL 脚本,因此没有从 SQL 脚本导入数据

https://learn.microsoft.com/en-us/ef/core/miscellaneous/testing/总结了可用的选项,但我仍然不知道在我们的例子中解决方案会是什么样子,因为我们需要

  • 能够将生产数据库中的数据匿名化为我们可以存储在 Git 中的状态。如果我们愿意,应该完成此同步,因此并非每次我们想要运行测试时都明确。我们无法手动写入数千行的插入。
  • 一种将数据库重置为每次测试运行之前保存的存储数据库的方法。

我们应该选择哪种内存数据库方法?

按照 OP 的要求将我的评论移动到答案:

根据你发布的有关测试 (https://learn.microsoft.com/en-us/ef/core/miscellaneous/testing) 的 EF Core 链接,很明显,不"建议"使用内存中(甚至 SQL Lite),因为你正在测试的内容不反映你的生产方案。有人可能会争辩说,你不应该测试数据库实现,但实际上大多数时候这是必要的。例如,我想测试我创建的视图是否返回预期的结果或报告是否正确生成,因此我认为使用像 OP 这样的完整 SQL Server 是一个有效的观点。另一点是,使用 SQL Lite 之类的东西并不能很好地支持使用 EF 可以进行的所有迁移。例如,我在创建索引时已经遇到了问题。

继续:您可以尝试解决此问题的一种方法是使用 Docker 容器。您可以在 Linux 容器中运行 SQL Server 使用 Docker 运行 SQL Server 容器映像。这个想法是,您可以基于 SQL Server 创建自定义映像,并在映像中放置 5000 行(或所需的任何数据),生成即用型映像并将其推送到 docker 注册表。

然后,在要使用预期数据运行测试的系统 CI 期间,启动所创建映像的 docker 容器,并让测试连接到该 SQL Server 实例(只需将端口映射到主机,通常为 1433)。这样,您可以保证测试始终以相同的数据集开始。

根据构建映像本身,您可以通过多种方式进行操作。您可以使用 CI 本身来创建映像。它可以从某个地方获取数据,或者让一个小程序为你生成数据并将其放入容器中。它可以是一个.bak文件,也可以是一个SQL脚本,其中包含由程序生成的一堆插入。然后,当您想要使用"新"数据的图像时,您需要做的就是运行 CI 构建。您可以将 then 标签添加到 Docker 映像,以确保您也可以针对新旧版本的数据运行测试,这很酷。

还需要考虑一些事情:您可能还需要在数据库更改(迁移)时注意更新映像,但您也可以通过始终从最新版本的架构创建映像或在 CI 过程中使用MigrateAsync应用迁移来生成映像。当然,这在很大程度上取决于您的数据库更改的频率。

我为Postgres数据库做了类似的事情,这些链接帮助我开始了。对于SQL Server来说,它也应该非常相似:

Docker提示 #79:在 Docker 映像中保存 Postgres 数据库

构建包含数据的 Docker 映像帖子

最新更新