Linq 基于实体框架的单元测试

Linq 基于实体框架的单元测试,linq,unit-testing,entity-framework,Linq,Unit Testing,Entity Framework,我想测试使用实体框架构建的实体。 我担心的是,使用实体框架意味着直接使用数据源。 那么,你知道如何对基于实体框架的组件进行单元测试吗?显然这很难。Erik在这里雄辩地提出-使用模拟框架怎么样? 在我看来,模拟框架可以帮助您将业务逻辑与数据库隔离开来。我同意,模拟框架是您所追求的。您创建了不从数据源检索的“模拟”对象,并测试该对象中的数据。我个人一直在使用Moq,我喜欢它——还有Rhinomock,还有其他的。您将希望使用模拟框架来检索模拟值,而不是访问真实数据。以下是一些模拟框架的列表,以及一些

我想测试使用实体框架构建的实体。 我担心的是,使用实体框架意味着直接使用数据源。
那么,你知道如何对基于实体框架的组件进行单元测试吗?

显然这很难。Erik在这里雄辩地提出-

使用模拟框架怎么样?
在我看来,模拟框架可以帮助您将业务逻辑与数据库隔离开来。

我同意,模拟框架是您所追求的。您创建了不从数据源检索的“模拟”对象,并测试该对象中的数据。我个人一直在使用Moq,我喜欢它——还有Rhinomock,还有其他的。

您将希望使用模拟框架来检索模拟值,而不是访问真实数据。以下是一些模拟框架的列表,以及一些帮助您入门的屏幕广播链接:

以下是一些关于如何开始的屏幕广播:


尽管示例可能过于简单,但我已尝试讨论解决此问题的可能方法。它包括关注点分离和我们亲爱的朋友依赖注入


如果您想了解更多详细信息,请与我联系。

我想与您分享其他信息。我还能够使用TypeMock隔离器测试基于实体框架的组件和应用程序。然而,它是商业性的

看看这篇文章:

由于Entity Framework的版本1打破了一些主要的软件设计原则,因此在应用程序中使用TDD时,实际上没有任何方法可以应用TDD。我的研究表明,如果你正在寻找一个即时的解决方案,那就是NHibernate。它的设计考虑到了单元测试

但是,如果您可以等待,那么实体框架的下一个版本似乎还有希望:

对于Enity Framework 4,这看起来很有希望:

项目的BookLibrary示例应用程序展示了如何对基于实体框架的应用程序进行单元测试。

一种便宜的方法是设置一个与实际数据库结构相同的数据库文件,并在单元测试配置中将连接字符串设置为指向那个数据库不需要拥有真实数据库拥有的所有表;正是单元测试所需要的

缺点是您需要管理数据库的状态,以便单元测试在运行期间和运行之间不会相互影响或相互影响

我知道当实际和单元测试数据库都使用SqlExpress时,这种方法是有效的,但我不知道如何在SqlExpress数据库中存根以获得完整的SQLDB

我意识到这在技术上是集成测试,但它可能比重构代码或学习模拟框架更便宜

实际连接字符串示例:

<add name="DrinksEntities" 
     connectionString="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient
     ;provider connection string=&quot;Data Source=localhost\sqlexpress;Initial Catalog=Drinks2;Integrated Security=True;MultipleActiveResultSets=True;Application Name=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" />
<add name="DrinksEntities" 
     connectionString="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient
     ;provider connection string=&quot;Data Source=.\SQLEXPRESS;attachdbfilename=|DataDirectory|\Inventory.mdf;Integrated Security=True;user instance=True;MultipleActiveResultSets=True;Application Name=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" />

单元测试连接字符串示例:

<add name="DrinksEntities" 
     connectionString="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient
     ;provider connection string=&quot;Data Source=localhost\sqlexpress;Initial Catalog=Drinks2;Integrated Security=True;MultipleActiveResultSets=True;Application Name=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" />
<add name="DrinksEntities" 
     connectionString="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient
     ;provider connection string=&quot;Data Source=.\SQLEXPRESS;attachdbfilename=|DataDirectory|\Inventory.mdf;Integrated Security=True;user instance=True;MultipleActiveResultSets=True;Application Name=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" />

这里是工作单元模式+内存数据库+t4代码生成的集合,用于自动生成伪EF dbContext

此时准确复制真实的EF db连接存在一些问题(无效的linq到EF查询和没有FK强制)

然而,拥有一个内存上下文来快速运行单元测试对于能够进行TDD或任何其他类型的以单元测试为中心的方法来说几乎是必不可少的


当我发现更多的问题时,我将在上面的链接上发布更新。

在经历了很多挫折之后,我终于找到了一个解决方案,至少在部分问题上我是满意的

首先使用存储库界面,如:

public interface IRepository
{
    IQueryable<T> GetObjectSet<T>();
}
公共接口IRepository
{
IQueryable GetObjectSet();
}
我们可以使用它返回内存中的集合或真实的DB支持的集合。接下来,将您的查询封装到一个查询对象中,该查询对象的接口如下所示

public interface IQuery<T>
{
    IQueryable<T> DoQuery(IQueryable<T> collection);
}
公共接口iquiry
{
IQueryable DoQuery(IQueryable集合);
}
现在将单元测试分为两组。第一组将测试您的查询是否有效。这样做:

[TestMethod]
public void TestQueryFoo()
{
     using(var repo = new SqlRepository("bogus connection string"))
     {
         var query = new FooQuery(); // implements IQuery<Foo>
         var result = query.DoQuery(repo.GetObjectSet<Foo>());  // as long as we don't enumerate the IQueryable EF won't notice that the connection string is bogus
         var sqlString = ((System.Data.Objects.ObjectQuery)query).ToTraceString(); // This will throw if the query can't be compiled to SQL
     }
}
[TestMethod]
公共void TestQueryFoo()
{
使用(var repo=newsqlrepository(“伪连接字符串”))
{
var query=new fookery();//实现IQuery
var result=query.DoQuery(repo.GetObjectSet());//只要我们不枚举IQueryable EF,就不会注意到连接字符串是假的
var sqlString=((System.Data.Objects.ObjectQuery)query).ToTraceString();//如果无法将查询编译为SQL,则会引发此错误
}
}
第二组单元测试可以自由地测试您的业务逻辑,而不必担心SQL编译步骤,到目前为止,这是我们遇到最多麻烦的地方


不管怎么说,它都不是完美的,触发器显然不会运行,DB实现的约束可能会被违反,并且可能会出现一些上下文和数据库不同步的问题。因此,尽管仍然需要端到端的集成测试,但可以发现在简单单元测试中运行时出现的最常见问题。

您可以使用内存数据库来测试实体框架模型。
查看更多详细信息

使用EF很难做到这一点。对于接口或可扩展POCO,您的答案是正确的。现在我们来读一下。很多EF测试的问题和答案都不是最新的,所以EF 4.0链接+1。我们的商店开始实施这里看到的技术,到目前为止似乎是答案。仅供参考,他从未在UnitOfWork类中处理上下文。在本例中,UnitOfWork类实现IDisposable。将这两种方法结合起来,用IDisposable装饰Hans答案中的IUnitOfWork界面,并实现Dispose模式。例如,到目前为止,这看起来是最好的解决方案