2010-09-01 9 views
7

Je suis en train de créer le contexte faux accodring à http://blogs.msdn.com/b/adonet/archive/2009/12/17/walkthrough-test-driven-development-with-the-entity-framework-4-0.aspxTester EF 4.0 avec des modèles POCO et t4 - Comment simuler le contexte?

Comme je peux voir qu'il est une interface qui expose des méthodes qui renvoie IObjectSet < ...>, mais les modèles T4 génère des méthodes qui retourne ObjectSet < ...> et il n'y a pas d'interface générée et sur cette page l'auteur ajoute l'interface au contexte créé et il lui donne la manière de créer le faux etc.

Mon but principal est d'utiliser des templates T4 pour générer des classes poco et créer un faux contexte pour tester mes dépôts personnalisés. Y at-il un moyen de le faire fonctionner sans écrire ou changer le modèle T4 ?? Comment puis-je créer des simulacres ci-dessus contexte (pour IObjectSet is't trivial) si elle est de retour au lieu de ObjectSet de IObjectSets ...

Thx à l'avance

Répondre

3

L'auteur est tout simplement se moquant du référentiel, pas les entités. EntityFramework génère ObjectQueries, mais il les enveloppe et son référentiel renvoie IObjectQueries. Il le fait afin qu'il puisse facilement se moquer des données, puis pendant la sauvegarde il valide simplement les entités.

Si vous essayez simplement de créer un référentiel «fantaisie», vous pouvez créer votre propre modèle T4, parcourir le fichier edmx et générer le code. Mais il n'y a aucune raison d'avoir à générer POCOS? Ils existent déjà, pourquoi avez-vous besoin de les recréer? Il a tout résumé dans un FakeObjectSet "générique" donc il n'y a vraiment pas beaucoup de code à écrire?

Êtes-vous essayer de générer ceci:

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

Si donc je vais vous deviner allez passer plus de temps avec T4 alors vous écrire juste.


Exemple T4 sans déclaration de classe ... vous pouvez faire la t4 complète en suivant 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)#>; 
<# 
} 

#> 

Ce qui générerait ce 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 est contenu dans System.Data il faut donc ajouter une référence à System.Data.Entity.dll

+0

Mayby j'étais miss compris, je suis juste basez cet article. Je sais que l'auteur a des classes POCOS, mais j'ai une grande BD déjà existante, j'ai dû créer edmx à partir de cette base de données et après beaucoup de difficultés (c'est Oracle DB), j'ai pu utiliser des templates T4 pour générer des classes POCO. Je ne les ai pas écrites auparavant à la main. Maintenant, je voulais ajouter des tests unitaires et je dois mocker mon objet de contexte si je veux tester des dépôts. T4 a donc généré des classes POCO pour les entités et la classe pour Context, mais il manquait une interface pour ce contexte, donc je ne peux pas créer de maquette en fonction de cette interface. – Simon

+1

Merci à http://slappyza.wordpress.com/2010/08/08/getting-the-entity-framework-to-generate-an-interface-for-mocking/ J'ai résolu le problème pour l'instant .. . :) – Simon

+0

+1. Vraiment, tout ce qui doit arriver est d'ajouter "I" aux déclarations "ObjectSet ..." existantes ... –

1

Citation en The Art Of Unit Testing par Roy Osherove:

Il n'y a pas de problème orienté objet qui ne peut pas être résolu en ajoutant une couche d'indirection, sauf, bien sûr, trop de couches d'indirection.

Ci-dessous est ma configuration EF4 POCO. Je n'ai pas utilisé T4 car il était trop difficile de déterminer comment nettoyer le gabarit pour ne pas générer trop de gumpf. Vous pouvez bien sûr pirater le gabarit T4 pour cracher quelque chose comme cette structure.

L'astuce était de créer le ObjectSet<T> s manuellement et de les exposer comme IQueryable.Parce que Add et Create sont sur ObjectSet<T>/ObjectSet<T>, j'ai également dû ajouter des méthodes pour ajouter et créer des entités.

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 
} 

Maintenant, vous remarquerez que le type de collection d'entités sur l'interface est IQueryable<T>, par opposition à IObjectSet<T>. Je ne pouvais pas être dérangé créant FakeObjectSet et IQueryable m'a fourni avec assez de flexibilité. Donc, pour KISS, j'ai réussi sans.

Mocking IQueryable, sur d'autre part, est 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()); 
    } 
}