使用 Effort.EF6 测试预加载场景
Testing eager-loading scenarios with Effort.EF6
我们正在使用 Effort.EF6 为针对内存数据库工作的 ASP.NET Web API 2 服务构建测试套件,在大多数情况下,这是一个很棒的经验.
但是,由于与此问题无关的原因,我们不得不关闭 EF6 中的延迟加载(通过 运行 Configuration.LazyLoadingEnabled = false;
在 db 上下文的构造函数中),这意味着如果我们忘记 .Include()
某处的关系并稍后使用它,我们会得到 NullReferenceExceptions
。我们希望我们的测试能够捕获这些类型的错误。
我们的测试设置基本如下:
- 使用 Effort 的连接工厂创建数据库连接。这是每个测试的唯一连接实例(具有唯一键,当我们尝试使用持久连接时)。
- 使用该连接创建一个数据库上下文,并添加我们希望用于测试的数据。
- 在数据库上下文的 DI 容器中注册服务覆盖。
问题是我们无法弄清楚如何配置 Effort.EF6 以禁止延迟加载,因为似乎我们在测试设置中添加到上下文的任何内容在测试代码运行时都已加载,因此我们永远不会看到例外。我们假设这是因为我们在测试设置和实际代码执行之间重新使用上下文实例。
如果我们尝试将第三步切换为以下步骤:
- 在 DI 容器中为数据库连接注册一个服务覆盖。
- DI容器创建数据库上下文实例(将数据库连接作为注入依赖)
我们最终得到了一个 空 数据库上下文,即尽管我们在 运行 测试之前添加了一些数据点,但它没有数据。
我们如何使用 Effort 构造和注入数据库上下文,如果缺少 .Include()
语句将失败,但如果存在则可以工作?
您也必须在 Effort.EF6 的构造函数中停用它 - 接受 DbConnection
对象的构造函数。
我为我的 EF Code First 项目解决了这个问题,如下所示:
public class MyDataContext : DbContext, IMyDataContext
{
/*
* the ohter stuff like IDbSet<T> etc.
*/
public MyDataContext() : base("name=MyConnectionString")
{
Configure();
}
/// <summary>
/// This constructor is for test usage only!
/// </summary>
/// <param name="connection">Test connection for in memory database</param>
public MyDataContext(DbConnection connection) : base(connection, true)
{
Configure();
}
/// <summary>
/// Configures the data context.
/// </summary>
private void Configure()
{
Configuration.LazyLoadingEnabled = false;
}
}
此外,在我的测试项目中,我正在设置测试 CSV 文件。 Effort.EF6 将使用这些文件来实例化具有种子数据的上下文。在我的例子中,我写了一个小的 TestDataManager,它提供了用特定文件为特定表播种的可能性。
这是一段代码,您可以如何使用 Effort.EF6 播种数据:
IDataLoader loader = new CsvDataLoader(@"C:\Temp\Test_CSV_Files");
DbConnection dbConnection = DbConnectionFactory.CreateTransient(loader);
var myDataContext = new MyDataContext(dbConnection);
也许这个 blog post 也能帮到你。
我们正在使用 Effort.EF6 为针对内存数据库工作的 ASP.NET Web API 2 服务构建测试套件,在大多数情况下,这是一个很棒的经验.
但是,由于与此问题无关的原因,我们不得不关闭 EF6 中的延迟加载(通过 运行 Configuration.LazyLoadingEnabled = false;
在 db 上下文的构造函数中),这意味着如果我们忘记 .Include()
某处的关系并稍后使用它,我们会得到 NullReferenceExceptions
。我们希望我们的测试能够捕获这些类型的错误。
我们的测试设置基本如下:
- 使用 Effort 的连接工厂创建数据库连接。这是每个测试的唯一连接实例(具有唯一键,当我们尝试使用持久连接时)。
- 使用该连接创建一个数据库上下文,并添加我们希望用于测试的数据。
- 在数据库上下文的 DI 容器中注册服务覆盖。
问题是我们无法弄清楚如何配置 Effort.EF6 以禁止延迟加载,因为似乎我们在测试设置中添加到上下文的任何内容在测试代码运行时都已加载,因此我们永远不会看到例外。我们假设这是因为我们在测试设置和实际代码执行之间重新使用上下文实例。
如果我们尝试将第三步切换为以下步骤:
- 在 DI 容器中为数据库连接注册一个服务覆盖。
- DI容器创建数据库上下文实例(将数据库连接作为注入依赖)
我们最终得到了一个 空 数据库上下文,即尽管我们在 运行 测试之前添加了一些数据点,但它没有数据。
我们如何使用 Effort 构造和注入数据库上下文,如果缺少 .Include()
语句将失败,但如果存在则可以工作?
您也必须在 Effort.EF6 的构造函数中停用它 - 接受 DbConnection
对象的构造函数。
我为我的 EF Code First 项目解决了这个问题,如下所示:
public class MyDataContext : DbContext, IMyDataContext
{
/*
* the ohter stuff like IDbSet<T> etc.
*/
public MyDataContext() : base("name=MyConnectionString")
{
Configure();
}
/// <summary>
/// This constructor is for test usage only!
/// </summary>
/// <param name="connection">Test connection for in memory database</param>
public MyDataContext(DbConnection connection) : base(connection, true)
{
Configure();
}
/// <summary>
/// Configures the data context.
/// </summary>
private void Configure()
{
Configuration.LazyLoadingEnabled = false;
}
}
此外,在我的测试项目中,我正在设置测试 CSV 文件。 Effort.EF6 将使用这些文件来实例化具有种子数据的上下文。在我的例子中,我写了一个小的 TestDataManager,它提供了用特定文件为特定表播种的可能性。
这是一段代码,您可以如何使用 Effort.EF6 播种数据:
IDataLoader loader = new CsvDataLoader(@"C:\Temp\Test_CSV_Files");
DbConnection dbConnection = DbConnectionFactory.CreateTransient(loader);
var myDataContext = new MyDataContext(dbConnection);
也许这个 blog post 也能帮到你。