2010-05-18 2 views
6

J'ai ce qui pourrait être vu comme un hybride bizarre de IQueryable<T> et IList<T> collections d'objets de domaine transmis ma pile d'applications. J'essaie de maintenir le plus possible le «chargement tardif» ou le «chargement paresseux». Je fais cela de deux façons:Comment puis-je tester ou tester mes fonctionnalités d'évaluation/d'exécution différées?

  1. En utilisant une couche de données LinqToSql et en passant à travers IQueryable<T> s par les dépôts et à ma couche d'application.
  2. Ensuite, après que ma couche d'application passe IList<T> s, mais où certains éléments dans le graphe d'objet/agrégat sont 'chained' with delegates afin de différer leur chargement. Parfois même le contenu du délégué dépend des sources IQueryable<T> et les DataContext sont injectés.

Cela fonctionne pour moi jusqu'à présent.

Ce qui est difficile, c'est de prouver que cette conception fonctionne réellement. C'est à dire. Si je défais la partie «fainéante» quelque part et que mon évaluation/exécution se passe tôt alors le tout est une perte de temps. Je voudrais être en mesure de TDD en quelque sorte.

Je ne connais pas grand-chose aux délégués ou à la sécurité des threads dans la mesure où elle s'applique aux délégués agissant sur la même source. Je voudrais être en mesure de se moquer du DataContext et en quelque sorte tracer les deux méthodes de différer (IQueryable<T> SQL et les délégués) le chargement afin que je puisse avoir des tests qui prouvent que les deux fonctions fonctionnent à différents niveaux/couches de l'application /empiler. Comme il est crucial que le différé fonctionne pour que le design ait une quelconque valeur, j'aimerais voir les tests échouer quand je casse le design à un niveau donné (séparé de l'implémentation en direct). Est-ce possible?

Répondre

4

A morelinq, nous avons une "séquence de rupture" pour tester cela. Fondamentalement, c'est un énumérateur qui va lancer une exception chaque fois qu'il est énuméré.

Il peut être aussi simple que:

internal sealed class BreakingSequence<T> : IEnumerable<T> 
{ 
    public IEnumerator<T> GetEnumerator() 
    { 
     throw new InvalidOperationException(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

Un test pour elle ressemble à ceci:

[Test] 
    public void XyzIsLazy() 
    { 
     var source = BreakingSequence<EntityClass>().AsQueryable(); 

     // inject it as your query source wherever appropriate 
     var query = source.Where(x=> true); 
     // does not throw, where does not enumerate the sequence 
    } 
+0

Cela ressemble à un début. Que diriez-vous quand j'ai un 'LazyItem ' qui utilise des délégués pour déclencher l'évaluation de l'élément encapsulé? http: // stackoverflow.com/questions/1669607/is-this-repository-pattern-efficace-with-linq-to-sql/1695561 # 1695561 –

+0

@cottsak: Vous pouvez définir le délégué comme étant un délégué de rupture (un délégué qui déclenche une exception). –

+0

Cela semble être une bonne idée. Peut-être que j'étais après une solution plus complexe quand ce n'était pas nécessaire. –

2

Je vais répondre dans une veine similaire à ce que Johannes Rudolph a répondu. Il semble que vous pensiez la bonne chose, voulant avoir un test pour quelque chose d'important qui serait difficile à tracer si elle échoue.

Je suggérerais certainement d'utiliser un simulacre à cette fin. Johannes a suggéré un objet qui jette l'exception quand il est énuméré. Puisque votre objet est modélisé, je crois que vous devriez être capable d'utiliser n'importe quel objet que vous voulez. Un cadre moqueur, tel que Rhino.Mocks (gratuit) ou TypeMock Isolator (cher), peut être très utile. Je recommande fortement de regarder dans des cadres moqueurs si vous ne l'avez pas déjà fait. Avec un simulacre en main, vous pouvez évaluer que les opérations doivent avoir lieu dans un certain ordre lorsque vous exécutez un certain code de test. Vous pouvez programmer votre maquette pour enregistrer quelles opérations ont lieu, puis vérifier l'enregistrement à la fin du test.

+0

+1 pour la suggestion d'enregistrement. J'ai utilisé des mocks très légèrement. J'ai vu les modèles "d'enregistrement" et cela pourrait être un excellent moyen de rassembler toute une série d'opérations complexes dans un test. Merci. –

+0

J'ai évalué TypeMock Isolator, mais j'ai décidé qu'il est trop cher à utiliser pour les quelques tests que je fais. Cependant, si vous allez tester beaucoup de choses comme ça, vous constaterez que cela rend souvent la configuration de vos tests beaucoup plus facile qu'avec les autres frameworks. –

+0

Je sais que Rhino Mocks s'occupe de l'enregistrement mais Moq suggère que "l'enregistrement" n'est pas génial et qu'il est conçu pour ne pas adhérer à cette approche - alors peut-être que je vais voir comment Moq pourrait satisfaire ce qui précède. Peut-être que cela nous inspirera sur la façon de tester cela. –