使用POCO和t4模板测试EF 4.0 - 如何模拟上下文?
我试图制造假上下文accodring到http://blogs.msdn.com/b/adonet/archive/2009/12/17/walkthrough-test-driven-development-with-the-entity-framework-4-0.aspx使用POCO和t4模板测试EF 4.0 - 如何模拟上下文?
,我可以看到有暴露返回IObjectSet < ...>方法的接口,但T4模板生成返回对象集< ...>方法并没有生成的接口,并在该页面的作者添加接口创建的上下文,并给他的方式来创建模拟等。
我的主要目标是使用T4模板生成poco类并创建模拟/假上下文来测试我的自定义存储库。有没有什么办法可以让它在没有写入或改变T4模板的情况下工作?如何创建上述背景下嘲弄(用于IObjectSet岂不等于简单),如果它的返回对象集的,而不是IObjectSets ...
THX提前
笔者只是嘲讽库,而不是实体。 EntityFramework生成ObjectQueries,但他包装它们,他的存储库返回IObjectQueries。他这样做,以便他可以轻松地嘲笑数据,然后在保存期间他只验证实体。
如果您只是想创建一个“模拟”存储库,您可以创建自己的T4模板并迭代edmx文件并生成代码。但是没有必要产生POCOS的理由?它们已经存在,为什么你需要重新创建它们?他将所有东西都抽象成一个“通用”的FakeObjectSet,所以实际上没有太多的代码要写入?
你想产生这样的:
public IObjectSet<Blog> Blogs
{
get
{
return _blogs ?? (_blogs = new FakeObjectSet<Blog>());
}
set
{
_blogs = value as FakeObjectSet<Blog>;
}
}
private FakeObjectSet<Blog> _blogs;
如果是的话我会想你要花费更多的时间与T4那么你就只是写它。
public IObjectSet<Blogs>{
get{
return _Blogs?? (_Blogs = FakeObjectSet<Blog>("Blogs"));
}
set{
_Blogs= value as FakeObjectSet<Class>("Blogs");
}
}
private FakeObjectSet<Blog> _Blogs;
旁注:
例T4无类的声明...您可以通过以下this blog
<#
foreach (EntitySet set in container.BaseEntitySets.OfType<EntitySet>())
{
#>
public IObjectSet<<#=MultiSchemaEscape(set.ElementType, code)#>>
{
get{
return <#=code.FieldName(set)#> ?? (<#=code.FieldName(set)#> = FakeObjectSet<<#=MultiSchemaEscape(set.ElementType, code)#>>("<#=set.Name#>"));
}
set{
<#=code.FieldName(set)#> = value as FakeObjectSet<<#=MultiSchemaEscape(set.ElementType, code)#>>("<#=set.Name#>");
}
}
private FakeObjectSet<<#=MultiSchemaEscape(set.ElementType, code)#>> <#=code.FieldName(set)#>;
<#
}
#>
这将生成的代码做完整的T4 。
IObjectSet被包含在System.Data所以添加引用罗伊Osherove到System.Data.Entity.dll
没有面向对象的问题,不能通过添加一个间接层来解决,当然除了间接层太多以外。
下面是我可嘲笑的EF4 POCO设置。我没有使用T4,因为它很难弄清楚如何清理模板以避免产生太多的垃圾。你当然可以破解T4模板来吐出像这样的结构。
诀窍是手动创建ObjectSet<T>
s并将它们暴露为IQueryable
。由于Add
和Create
位于ObjectSet<T>
/ObjectSet<T>
,我还必须添加添加和创建实体的方法。现在
public interface IStackTagzContext {
IQueryable<Question> Questions { get; }
Question CreateQuestion();
void CreateQuestion(Question question);
void SaveChanges();
}
public class StackTagzContext : ObjectContext, IStackTagzContext {
public StackTagzContext() : base("name=myEntities", "myEntities")
{
base.ContextOptions.LazyLoadingEnabled = true;
m_Questions = CreateObjectSet<Question>();
}
#region IStackTagzContext Members
private ObjectSet<Question> m_Questions;
public IQueryable<Question> Questions {
get { return m_Questions; }
}
public Question CreateQuestion() {
return m_Questions.CreateObject();
}
public void AddQuestion(Question question) {
m_Questions.AddeObject(question);
}
public new void SaveChanges() {
base.SaveChanges();
}
#endregion
}
,你会注意到在接口上的实体集合类型IQueryable<T>
,而不是IObjectSet<T>
。我不能打扰FakeObjectSet
和IQueryable
为我提供了足够的灵活性。所以为了KISS,我没有它。
嘲笑IQueryable
,在另一方面,是微不足道的:
using Moq;
[TestClass]
public class TestClass {
Mock<IStackTagzContext> m_EntitiesMock = new Mock<IStackTagzContext>();
[TestMethod()]
public void GetShouldFilterBySite() {
QuestionsRepository target = new QuestionsRepository(m_EntitiesMock.Object);
m_EntitiesMock.Setup(e=>e.Questions).Returns(new [] {
new Question{Site = "site1", QuestionId = 1, Date = new DateTime(2010, 06,23)},
}.AsQueryable());
}
}
Mayby我怀念的理解,我只是立足这篇文章。我知道作者有POCOS类,但是我有大的已经存在的数据库,我必须从这个数据库创建edmx,然后在很多困难之后(这是Oracle数据库),我能够使用T4模板生成POCO类,因为我没有亲手写下他们。现在我想添加单元测试,如果要测试存储库,我必须模拟我的上下文对象。 因此,T4为Context创建了实体和类的POCO类,但是这个上下文缺少接口,所以我无法基于此接口创建模拟。 – Simon 2010-09-01 13:25:47
感谢 http://slappyza.wordpress.com/2010/08/08/getting-the-entity-framework-to-generate-an-interface-for-mocking/ 我现在已经解决了问题.. 。:) – Simon 2010-09-01 13:26:33
+1。真的,所有需要发生的事情就是将'I'添加到现有的ObjectSet ...声明中... – 2010-09-01 13:29:14