我想测试使用实体框架构建的实体。我担心的是,使用实体框架意味着直接使用数据源。那么有什么想法如何对基于Entity Framework的组件进行单元测试?
Answers:
对于Enity Framework 4,这看起来很有希望:可测试性和Entity Framework 4.0
显然这很难。Erik雄辩地将其放在此处-TDD和ADO.NET实体框架
一种便宜的方法是设置一个与真实数据库具有相同结构的数据库文件,并在单元测试配置中设置连接字符串以指向该文件。数据库并不需要拥有真正的所有表。只是单元测试所需要的。
缺点是您需要管理数据库的状态,以使单元测试在运行期间和运行之间不会互相影响。
我知道当实际和单元测试DB都使用SQL Express时,这种方法有效,但是我不知道在SqlExpress DB中存根以获得完整的SQL DB。
我意识到这是技术上的集成测试,但是它比重构代码或学习模拟框架要便宜。
实际连接字符串示例:
<add name="DrinksEntities"
connectionString="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient
;provider connection string="Data Source=localhost\sqlexpress;Initial Catalog=Drinks2;Integrated Security=True;MultipleActiveResultSets=True;Application Name=EntityFramework""
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="Data Source=.\SQLEXPRESS;attachdbfilename=|DataDirectory|\Inventory.mdf;Integrated Security=True;user instance=True;MultipleActiveResultSets=True;Application Name=EntityFramework""
providerName="System.Data.EntityClient" />
我想分享另一点意见。我还能够使用TypeMock Isolator测试基于Entity Framework的组件和应用程序。但是,这是商业性的。
看一下这篇文章: 使用TypeMock隔离器介绍实体框架单元测试
由于Entity Framework版本1违反了一些主要的软件设计原则,因此在您的应用程序中使用TDD时,实际上没有任何方法可以使用它。如果您正在寻找即时解决方案,我的研究指向NHibernate。它的设计考虑了单元测试。
但是,如果您可以等待,那么下一个版本的Entity Framework似乎就有希望: Entity Framework 4.0的测试驱动开发演练
尽管示例可能非常简单,但是我尝试讨论解决此问题的可能解决方案。它涉及到关注点的分离和我们亲爱的朋友Dependency Injection。
如果需要更多详细信息,请与我联系。
在对此感到无奈之后,我终于有了至少对部分问题感到满意的解决方案。
首先使用存储库接口,例如:
public interface IRepository
{
IQueryable<T> GetObjectSet<T>();
}
我们可以使用它返回内存中的集合或真实的数据库支持的集合。接下来,将查询封装到带有如下所示接口的查询对象中。
public interface IQuery<T>
{
IQueryable<T> DoQuery(IQueryable<T> collection);
}
现在将您的单元测试分为2组。第一组将测试您的查询是否有效。这样做是这样的:
[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
}
}
然后,第二组单元测试可以自由地测试您的业务逻辑,而不必担心SQL编译步骤(到目前为止,这是我们遇到的最大麻烦)。
无论如何,它都不是完美的,显然不会运行触发器,可能会违反数据库实现的约束,并且上下文和数据库不同步的某些问题会出现。因此,尽管仍然需要端到端集成测试,但有可能发现在简单的单元测试中,IMO在运行时最常见的问题。
WPF应用程序框架(WAF)项目的BookLibrary示例应用程序显示了如何对基于实体框架的应用程序进行单元测试。
这是工作单元模式+内存数据库+ t4代码生成的汇总,以自动生成伪造的EF dbContext。
http://mockingcompetence.wordpress.com/2013/05/20/fakingefdatacontext/
目前完全复制真实的EF数据库连接存在一些问题(对EF查询的无效linq且无FK强制执行)。
但是,具有内存上下文来快速运行单元测试对于能够进行TDD或任何其他类型的以单元测试为中心的方法几乎至关重要。
当我发现更多问题时,将在上面的链接中发布更新。