测试 Entity Framework Core





5.00/5 (2投票s)
如何使用 Entity Framework Core 编写自动化测试。
引言
在这篇文章中,我们将看看如何使用 Entity Framework Core 编写自动化测试。
就像之前的文章一样,代码可以在 这里找到。
故事
不久前,在做一个项目时,我想用一个模拟数据库做一个集成测试,这样我就可以验证数据库约束实际上是否有效,并且配置是否正确。
因此,为了找到一个可行的解决方案,既能完成工作,又不会在处理能力和清理方面带来太多开销,我最终找到了 这个文档页面。
如果您浏览了文档页面,您会发现该文档实际上为此指定了两种方法。
所以在浏览了这两种方法之后,我认为 InMemory 方法对我来说更好,因为我不想包含对 SQLite 的额外依赖。
嗯,在按照例子实现之后,我发现它实际上并不是我所需要的,这主要是因为两个主要原因
- InMemory 数据库需要一个名称。 这样做的原因是为了让您可以在测试中使用同一个数据库。这对我来说主要是个麻烦,因为我不想在每个测试中都重新创建数据库,如果我能避免重复,那就更好了。
- InMemory 数据库不是关系数据库,它根本算不上是一个数据库,因为我艰难地发现,我配置到数据库上下文中的所有约束甚至都没有被验证。 如果我没有遵循测试驱动开发方法,那么我会在手动测试或更糟糕的情况下(在生产环境中)发现我的代码中的一个错误。
这引出了这篇文章的主题,使用 SQLite 进行内存测试,重用功能,甚至检查生成的查询。
设置
首先,我们将创建一个新的 ASP.NET Core MVC 项目,该项目具有单独的身份验证(这主要是因为它已经配置了数据库上下文,当然,您可以构建自己的)。
下一步,也是我们将完成大部分工作的地方,是测试项目。 为此,我们需要一个 .NET Core 控制台项目。
一旦我们有了测试项目并引用了我们的 WebApplication
项目(以便我们可以访问 DbContext
),我们就需要安装一些 Nuget 包
Microsoft.NET.Test.Sdk
(15.7.2)- 这是运行单元测试所必需的。
NUnit
(3.10.1)- 我选择的测试框架,尽管您可以使用任何适合您需求的框架。
NUnit3TestAdapter
(3.10)- 这样 ReSharper 和 Visual Studio 就可以找到并运行测试。
Microsoft.AspNetCore.App
- 安装此包是因为我们使用了
IdentityDbContext
,但这仅仅是因为我为这个例子选择使用的模板。
- 安装此包是因为我们使用了
Microsoft.EntityFrameworkCore.Sqlite
(2.1.0)
实现
现在我们拥有了我们需要的一切,让我们继续实现。
出于习惯,在测试项目内部,我通常创建一个名为 TestUtilities 的文件夹,并在其中创建一个名为 TestDatabaseContextFactory
的 static
类。
我逐行注释了该类,以解释每件事的作用。
namespace Test.TestUtilities
{
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using WebApplication.Data;
public static class TestDatabaseContextFactory
{
public static ApplicationDbContext CreateDbContext()
{
DbContextOptionsBuilder<ApplicationDbContext>
contextOptionsBuilder = // declaring the options we are going to use
// for the context we will be using for tests
new DbContextOptionsBuilder<ApplicationDbContext>();
LoggerFactory loggerFactory = new LoggerFactory(); // this will allow us to add
// loggers so we can actually inspect what code and queries EntityFramework produces.
loggerFactory
.AddDebug() // this logger will log to the Debug output
.AddConsole(); // this logger will output to the console
SqliteConnectionStringBuilder connectionStringBuilder =
new SqliteConnectionStringBuilder { Mode = SqliteOpenMode.Memory }; // this is more
// syntax friendly approach to defining and InMemory connection string for our
// database, the alternative is to write it out as a string.
SqliteConnection connection =
new SqliteConnection(connectionStringBuilder.ConnectionString); // create a
// connection to the InMemory database.
connection.Open(); // open the connection
contextOptionsBuilder.UseLoggerFactory(loggerFactory); // register the loggers
// inside the context options builder, this way, entity framework logs the queries
contextOptionsBuilder.UseSqlite(connection); // we're telling entity framework
// to use the SQLite connection we created.
contextOptionsBuilder.EnableSensitiveDataLogging(); // this will give us more
// insight when something does go wrong. It's ok to use it here since it's a
// testing project, but be careful about enabling this in production.
ApplicationDbContext context =
new ApplicationDbContext(contextOptionsBuilder.Options); // creating the actual DbContext
context.Database.EnsureCreated(); // this command will create the schema
// and apply configurations we have made in the context, like relations and constraints
return context; // return the context to be further used in tests.
}
}
}
有了这个,我们现在就可以在我们的测试中使用它,如下所示
namespace Test
{
using NUnit.Framework;
using Test.TestUtilities;
using WebApplication.Data;
[TestFixture]
public class TestingDatabaseCreation
{
[Test]
public void TestCreation()
{
ApplicationDbContext context = TestDatabaseContextFactory.CreateDbContext();
}
}
}
即使这个测试没有断言任何东西,它仍然会通过,并且附带的好处是,如果我们查看测试运行的输出,我们将看到针对数据库运行的所有查询。
结论
这可能看起来不多,但它已成为我项目中使用的标准,因为即使单元测试的想法很好,但有时我们的测试需要小而快,但仍然执行实际的应用程序逻辑,这通常尤其是当使用 SQL 时,功能不仅仅存在于应用程序内部。
请记住,这种方法使用 SQLite,因此如果您使用其他数据库或 NoSQL 数据库,请查看它们是否具有内存中变体。 话虽如此,SQLite 和 SQL Server 也是不同的,但我们使用 Entity Framework 的 9/10 功能都存在于两者中。
我希望您喜欢这篇文章,并且未来还有一些其他与 Entity Framework Core 相关的文章。
祝好!