0

J'utilise NHibernate et j'ai beaucoup de dépôts, qui héritent tous d'une classe de base NHibernateRepository. Voici un de mes dépôts:Comment se moquer d'une classe de base en utilisant une structure de carte?

public class StaffRepository : NHibernateRepository<IStaff>, 
{ 
    public IEnumerable<IStaff> GetBySiteRegionAndMonth(int siteId, int regionId, DateTime firstOfMonth) 
    { 
     return Repository.Where(ab => ab.SiteId == siteId && ab.WorkDate >= firstOfMonth && ab.WorkDate < firstOfMonth.AddMonths(1)); 
    } 
} 

Et la classe de base:

public class NHibernateRepository<TEntity> : IRepository<TEntity> where TEntity : IEntity 
{ 
    protected ISession session; 

    public NHibernateRepository() 
    { 
     this.session = new SessionCache().GetSession(); 
    } 

    public IQueryable<TEntity> Query 
    { 
     get 
     { 
      return session.Query<TEntity>(); 
     } 
    } 

    // Add 
    public void Add(TEntity entity) 
    { 
     session.Save(entity); 
    } 

    // GetById 
    public TEntity GetById(int id) 
    { 
     // return session.Load<TEntity>(id); 
     return this.Query.SingleOrDefault(e => e.Id == id); 
    } 
} 

J'essaie maintenant de se moquer de la classe de base NHibernateRepository utilisant une classe de test qui ne sera pas accéder à une base de données réelle, mais utilisera plutôt une liste statique. Voici mon inscription de la classe de test dans ma structure conteneur carte:

x.For(typeof(IRepository<>)).Use(typeof(TestNHibernateRepository<>)); 

Mon problème est que le vrai NHibernateRepository est encore utilisé dans les tests. J'utilise le StaffRepository réel selon mon inscription:

x.For<IStaffRepository>().Singleton().Use<StaffRepository>(); 

Toutes mes autres classes d'essai sont injectés très bien, mais je pense que cela est problématique, car il est une classe héritée. Comment puis-je m'assurer que mon StaffRepository utilise le TestNHibernateRepository au lieu de NHibernateRepository?

Répondre

3

Bien qu'il soit facile de créer une fausse implémentation, vos tests unitaires seront très peu fiables, car votre référentiel expose IQueryable<T> et cela provoque tight coupling et cela provoquera toujours une fuite de l'implémentation spécifique.

Cela signifie que si vous utilisez un LINQ pour objets la mise en œuvre sur IQueryable<T> dans vos tests unitaires, presque toutes les requêtes LINQ que vous écrivez sur IQueryable<T> toujours réussir, alors qu'ils pourraient très bien échouer lorsque vous utilisez le fournisseur de requête NHibernate. Au lieu de cela, vous devez tester les classes qui dépendent de IRepository<T> en utilisant les tests d'intégration, ce qui signifie que vous communiquez avec la base de données réelle, et non pas une mise en attente en mémoire. Les tests unitaires doivent être effectués à un niveau différent.

Même si IQueryable<T> est une interface, ce n'est pas vraiment une abstraction, ou du moins, c'est ; un Dependency Inversion Principle violation. Donc, à la place, vous devez vous assurer que IQueryable<T> est utilisé uniquement dans votre couche d'accès aux données.

Une solution très efficace que j'ai trouvé à cela, est l'utilisation de query handlers, où les objets de requête (les données) fait partie d'une couche de base, tandis que leurs gestionnaires (qui utilisent un O/RM sous la forme de IQueryable<T>) font partie de la couche d'accès aux données. Votre test d'intégration permet de tester ces gestionnaires, tandis que les utilisateurs de ces gestionnaires peuvent à nouveau faire l'objet de tests unitaires.