使用entity framework进行unit testing
我想testing使用Entity Framework构build的实体。 我担心的是使用entity framework意味着直接使用数据源。 那么任何想法如何unit testing基于entity framework的组件?
对于Enity Framework 4,这看起来很有希望: 可testing性和entity framework4.0
显然这很难。 Erik在这里雄辩地说: TDD和ADO.NETentity framework
一个便宜的方法是build立一个与你的真实数据库具有相同结构的数据库文件,并在你的unit testingconfiguration中设置连接string来指向它。 数据库不需要拥有真正的所有表; 只是unit testing需要的。
缺点是您需要pipe理数据库的状态,以便在运行期间和运行期间,unit testing不会互相影响。
我知道这种方法适用于真正的unit testing数据库使用SQL Express,但我不知道SqlExpress数据库中的完整SQL数据库存根。
我意识到这是技术上的集成testing,但它可能比重构代码或学习嘲笑框架便宜。
示例实际连接string:
<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" />
示例unit testing连接string:
<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" />
你将要使用一个模拟框架来检索模拟值而不是实际的数据。 以下是一些模拟框架的列表,以及一些截屏video的链接,以帮助您开始使用:
-
犀牛嘲笑
-
起订量
以下是关于如何开始的一些截屏:
- Moq介绍嘲弄
- 犀牛嘲笑video
我想分享另一个意见。 我能够使用TypeMock Isolatortesting基于entity framework的组件和应用程序。 但是它是商业的。
看看这篇文章: 用TypeMock Isolator介绍Entity Frameworkunit testing
由于entity framework的第一版打破了一些主要的软件devise原则,所以在你的应用程序中使用TDD实在没有办法。 我的研究指向NHibernate,如果你正在寻找一个直接的解决scheme。 它的devise考虑了unit testing。
但是,如果您可以等待,下一个entity framework版本似乎有希望: 使用entity framework4.0进行testing驱动的开发演练
虽然这些例子可能非常简单,但我试图讨论解决这个问题的可能办法。 它涉及问题的分离和我们亲爱的朋友dependency injection。
联系我,如果你想了解更多的细节。
我同意,一个嘲弄的框架是你所追求的。 您可以创build不会从数据源中检索到的“模拟”对象,然后testing该对象中的数据。 我个人一直在和Moq合作,我喜欢它 – 还有Rhinomocks,还有其他的。
在经历了很多挫折之后,我终于有了一个解决scheme,至less对于部分问题我很满意。
首先使用一个存储库接口,如:
public interface IRepository { IQueryable<T> GetObjectSet<T>(); }
我们可以使用它返回内存集合或实际的数据库备份集合。 接下来,将查询封装到查询对象中,并使用类似于此的界面。
public interface IQuery<T> { IQueryable<T> DoQuery(IQueryable<T> collection); }
现在把你的unit testing分成两组。 第一组将testing您的查询是否有效。 这样做是这样的:
[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 } }
第二组unit testing可以自由地testing您的业务逻辑,而不必担心SQL编译步骤,而这个步骤到目前为止是我们遇到的最麻烦的地方。
它的想象力并不完美,触发器显然不会被运行,数据库实现的约束可能被违反,并且上下文和数据库不同步的一些问题会突然出现。 因此,虽然端到端集成testing仍然需要,但可以在简单的unit testing中捕捉什么是IMO在运行时突然出现的最常见问题。
WPF应用程序框架(WAF)项目的BookLibrary示例应用程序显示了如何对基于entity framework的应用程序进行unit testing。
下面是工作模式+内存数据库+ t4代码生成单元的聚合,以自动生成伪造的EF dbContext。
http://mockingcompetence.wordpress.com/2013/05/20/fakingefdatacontext/
有一些问题(对EF查询无效的linq和没有FK的执行)与此时正好复制一个真正的EF db连接。
但是,使用内存上下文来快速运行unit testing对于能够执行TDD或任何其他types的以unit testing为中心的方法来说几乎是必不可less的。
我会发布更新到上面的链接,因为我找出更多的问题。
您可以使用内存数据库来testing您的entity framework模型。 在这里寻找更多的细节
如何使用模拟框架? 在我看来,一个模拟框架可以帮助你从数据库中分离你的业务逻辑。