实体框架是不是有内存提供程序?
Posted
技术标签:
【中文标题】实体框架是不是有内存提供程序?【英文标题】:Is there an in-memory provider for Entity Framework?实体框架是否有内存提供程序? 【发布时间】:2010-10-09 04:17:57 【问题描述】:我是针对 ADO .NET 实体框架编写的单元测试代码。我想用行填充内存数据库,并确保我的代码正确检索它们。
我可以使用 Rhino Mocks 模拟实体框架,但这还不够。我会告诉查询要返回给我的实体。这既不会测试 where 子句也不会测试 .Include() 语句。我想确保我的 where 子句只匹配我想要的行,而不匹配其他行。我想确保我已经要求了我需要的实体,而我不需要。
例如:
class CustomerService
ObjectQuery<Customer> _customerSource;
public CustomerService(ObjectQuery<Customer> customerSource)
_customerSource = customerSource;
public Customer GetCustomerById(int customerId)
var customers = from c in _customerSource.Include("Order")
where c.CustomerID == customerId
select c;
return customers.FirstOrDefault();
如果我模拟 ObjectQuery 以返回填充订单的已知客户,我如何知道 CustomerService 具有正确的 where 子句和 Include?我宁愿插入一些客户行和一些订单行,然后断言选择了正确的客户并填充了订单。
【问题讨论】:
就像你最终做的那样,我使用接口来遵循存储库模式和工作单元模式。然后,我有两个命名空间-> EF 和 Fake。在我的 Fake 存储库中,我只是使用 IListEF7(预发布)中包含一个 InMemory 提供程序。
您可以使用NuGet package,也可以在 GitHub 上的EF repo (view source) 中了解它。
【讨论】:
虽然确实如此,但 EF7 仍然是预发布版本,并且 Microsoft 已声明 EF7 不仅仅是 EF6 的下一个版本;这就是为什么他们将其重命名为 EF Core 1.0 我们的团队决定在复杂类型和 TPT 实施之前不接触 EF7。 EF7 太原始了。【参考方案2】:文章http://www.codeproject.com/Articles/460175/Two-strategies-for-testing-Entity-Framework-Effort 描述了Effort - 在内存中运行的实体框架提供程序。
您仍然可以在单元测试中使用您的 DbContext 或 ObjectContext 类,而无需拥有实际的数据库。
【讨论】:
【参考方案3】:这里更好的方法可能是使用存储库模式来封装您的 EF 代码。在测试你的服务时,你可以使用 mocks 或 fakes。在测试您的存储库时,您需要访问真实的数据库,以确保您获得预期的结果。
【讨论】:
如果我只是模拟存储库以返回给定的客户,这不会测试规范。我想在单元测试中包含规范,而不是等到我使用真正的数据库。 Lol.. 以及如何使用 Repository 模式测试 LINQ2Entities 查询?没有办法做到这一点,因为这些查询会生成 sql 查询,我们也需要在数据库中测试它们。 我接受这个答案,因为它是我实际所做的最接近的事情。我以存储库模式的形式创建了接口,然后实现了一个 EF 适配器和一个内存测试工具。它不会测试数据库,但会测试我自己的规范。 是的,将 Moq 与 InMemoryDbSet 一起使用。这不适用于外连接,但适用于内连接 LINQ 查询。 基于 DbContext 的存储库是一种泄漏抽象,其危害比任何事情都大。【参考方案4】:目前没有用于 EF 的内存提供程序,但如果您查看 Highway.Data,它有一个基本抽象接口和一个 InMemoryDataContext。
Testing Data Access and EF with Highway.Data
【讨论】:
这不再是正确答案。 EF7 现在支持 InMemory ......好吧,当它在不久的将来发布时。 在撰写本文时它处于测试阶段。在 NuGet 上查找 EntityFramework.InMemory。 虽然 EF7 将包含一个 InMemory 提供程序...据我了解,InMemory 提供程序是高度抽象的,因为它模仿了所有提供程序的共同特征。对于需要验证某些特定于提供程序的概念的单元测试,您需要使用 EntityFramework.SqlLite 提供程序之类的东西。例如,我无法使用 InMemory 提供程序验证唯一约束或必填字段约束。您也无法使用它验证关系约束。更多细节在这里:github.com/aspnet/EntityFramework/issues/2166 FWIW,我们反对实时开发数据库(因为无论如何我们都积极地将它用于沙箱),并且只是将测试类包装在事务范围中。 msdn.microsoft.com/en-us/library/aa833153(v=vs.100).aspx【参考方案5】:是的,至少有一个这样的提供商 - SQLite。我已经使用了一点,它的工作原理。你也可以试试SQL Server Compact。它是一个嵌入式数据库,也有 EF 提供程序。 编辑: SQLite 支持内存数据库 (link1)。您只需要指定一个连接字符串,例如:“Data Source=:memory:;Version=3;New=True;”。如果您需要示例,可以查看SharpArchitecture。
【讨论】:
我可以使用嵌入式(进程内)数据库,但我更喜欢完全在内存中。我想定义我的表并在代码中完全填充一些行,并且从不将任何内容写入磁盘。然后我可以让单元测试验证我的 CustomerService 是否正确查询了该数据。 我更喜欢在内存中运行实际的数据库,因为要测试的最重要的事情是数据库关系和约束,而您在代码中对此几乎没有支持。困扰我的是,这是应用程序逻辑,应该在您的模型中而不是在数据库中表示。 完美的是某种 .net 集合,它可以模仿数据库表、它们的关系和约束,这将允许完全在内存中创建数据库,并允许您创建 ddl 以导出完成测试后到你的真实数据库 对 ORM 使用 NHibernate。数据库的结构将与您的实体一起呈现。而且这种结构可以很容易地导出到许多不同的数据库中(尤其是当您使用 DDD 时)。并且可以使用内存中的 SQLite db 轻松对其进行测试。有关示例,请参阅 SharpArchitecture。 请注意,如果模型包含时间数据类型,那么实体框架中的 SQLite 目前似乎不支持:***.com/questions/32097637/…(我尝试使用 SQLite nuget 包 v1.0.105.1)。 【参考方案6】:我不熟悉 Entity Framework 和 ObjectQuery 类,但如果 Include 方法是虚拟的,您可以像这样模拟它:
// Arrange
var customerSourceStub = MockRepository.GenerateStub<ObjectQuery<Customer>>();
var customers = new Customer[]
// Populate your customers as if they were coming from DB
;
customerSourceStub
.Stub(x => x.Include("Order"))
.Return(customers);
var sut = new CustomerService(customerSourceStub);
// Act
var actual = sut.GetCustomerById(5);
// Assert
Assert.IsNotNull(actual);
Assert.AreEqual(5, actual.Id);
【讨论】:
GetCustomerById 方法有两个特点:where 子句和 include。如果我模拟客户来源以返回一个已知客户,我不会测试它们。 如果您模拟 Include 方法,您不会返回已知客户,而是返回已知客户的列表,因此您可以测试 where 子句以查看它是否通过其 id 找到客户。就 Include 方法而言,您还要验证您是否使用正确的参数调用它:Order【参考方案7】:您可以尝试SQL Server Compact,但它有一些非常严重的限制:
SQL Server Compact 在与实体框架一起使用时不支持分页查询中的 SKIP 表达式 SQL Server Compact 在与实体框架一起使用时不支持具有服务器生成的键或值的实体 没有外部连接、整理、对浮点数取模、聚合【讨论】:
【参考方案8】:在EF Core 中有两个主要选项:
-
SQLite in-memory mode 允许您针对行为类似于关系数据库的提供程序编写有效的测试。
The InMemory provider 是一个轻量级的提供程序,具有最小的依赖关系,但并不总是像关系数据库一样工作
我正在使用 SQLite,它支持我需要对 Azure SQL 生产数据库执行的所有查询。
【讨论】:
以上是关于实体框架是不是有内存提供程序?的主要内容,如果未能解决你的问题,请参考以下文章
当 WCF 服务到 TCP/IP 时,底层提供程序在开放实体框架上失败
找不到具有不变名称“System.Data.SqlClient”的 ADO.NET 提供程序的实体框架提供程序。