Testing EF 4.0 with POCO and t4 Templates - What is the context layout?

I am trying to create a fake accodring context for http://blogs.msdn.com/b/adonet/archive/2009/12/17/walkthrough-test-driven-development-with-the-entity-framework-4-0.aspx

As I can see, there is an interface that provides methods that return an IObjectSet <...>, but T4 templates generate methods that return an ObjectSet <...> and there is no interface created, and on this page the author adds an interface to the created context , and he gives him a way to create a layout, etc.

My main goal is to use T4 templates to create poco classes and create a layout / fake context for testing my custom repositories. Is there a way to make it work without writing or modifying the T4 template? How can I create mocks above the context (there is no trivial for IObjectSet) if it returns an ObjectSet instead of IObjectSets ...

thanks in advance

+7
c # entity-framework-4 t4
source share
2 answers

The author simply makes fun of the repository, not the entity. EntityFramework generates ObjectQueries, but it wraps them, and its repository returns IObjectQueries. He does this so that he can easily mock the data, and then during the save he simply checked the entities.

If you are just trying to create a "mock" repository, you can create your own T4 template and iterate over the edmx file and generate the code. But there is no reason to create POCOS? They already exist, why do you need to recreate them? He abstracted everything into a β€œcommon” FakeObjectSet, so there really isn’t much code written?

You are trying to generate this:

public IObjectSet<Blog> Blogs { get { return _blogs ?? (_blogs = new FakeObjectSet<Blog>()); } set { _blogs = value as FakeObjectSet<Blog>; } } private FakeObjectSet<Blog> _blogs; 

If so, I'm going to guess that you will spend more time on T4, then you just write it.


T4 example without class declaration ... you can make full t4 by running 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)#>; <# } #> 

To generate this code:

 public IObjectSet<Blogs>{ get{ return _Blogs?? ( _Blogs = FakeObjectSet<Blog>("Blogs")); } set{ _Blogs= value as FakeObjectSet<Class>("Blogs"); } } private FakeObjectSet<Blog> _Blogs; 

Side note.

IObjectSet is contained in System.Data, so add a link to System.Data.Entity.dll

+3
source share

Quote to The Art of Testing Units from Roy Osherov:

There is no object-oriented problem that cannot be solved by adding a layer of indirection, except, of course, too many layers of indirection.

Below is my EF4 POCO mock setup. I did not use T4 as it was too difficult to figure out how to clear the template so as not to generate too much gumpf. Of course, you can hack the T4 template to spit out something like this structure.

The trick was to create an ObjectSet<T> manually and set them as IQueryable . Since Add and Create are on ObjectSet<T> / ObjectSet<T> , I also had to add methods to add and create entities.

 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 } 

Now you will notice that the type of entity collection is on the IQueryable<T> interface, not the IObjectSet<T> . I could not worry about creating FakeObjectSet and IQueryable , giving me enough flexibility. So for KISS I went around without it.

IQueryable , on the other hand, is trivial:

 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()); } } 
+1
source share

All Articles