2009-05-04 6 views
9

j'ai besoin récemment de construire un arbre d'expression j'ai donc écrit une méthode d'essai comme si ...Unité des arbres d'expression d'essai

/// <summary> 
    /// 
    /// </summary> 
    [TestMethod()] 
    [DeploymentItem("WATrust.Shared.Infrastructure.dll")] 
    public void BuildForeignKeysContainsPredicate_shoud_build_contains_predicate() 
    { 
     RemoteEntityRefLoader_Accessor<ReferencedEntity> target = CreateRemoteEntityRefLoader_Accessor(); 

     List<object> foreignKeys = new List<object>() { 1, 2, 3, 4 }; 
     Expression<Func<ReferencedEntity, bool>> expected = (ReferencedEntity referencedEntity) => foreignKeys.Contains(referencedEntity.Id); 
     Expression<Func<ReferencedEntity, bool>> actual; 

     actual = target.BuildForeignKeysContainsPredicate(foreignKeys, "Id"); 

     Assert.AreEqual(expected.ToString(), actual.ToString()); 
    } 

Quand j'ai finalement obtenu la méthode « BuildForeignKeysContainsPredicate » Je travaille pourrais jamais Teh test passer ... Voici la méthode:

/// <summary> 
    /// 
    /// </summary> 
    /// <param name="foreignKeys"></param> 
    /// <returns></returns> 
    private Expression<Func<TReferencedEntity, bool>> BuildForeignKeysContainsPredicate(List<object> foreignKeys, string primaryKey) 
    { 
     Expression<Func<TReferencedEntity, bool>> result = default(Expression<Func<TReferencedEntity, bool>>); 

     try 
     { 
      ParameterExpression entityParameter = Expression.Parameter(typeof(TReferencedEntity), "referencedEntity"); 
      ConstantExpression foreignKeysParameter = Expression.Constant(foreignKeys, typeof(List<object>)); 
      MemberExpression memberExpression = Expression.Property(entityParameter, primaryKey); 
      Expression convertExpression = Expression.Convert(memberExpression, typeof(object)); 
      MethodCallExpression containsExpression = Expression.Call(foreignKeysParameter 
       , "Contains", new Type[] { }, convertExpression); 

      result = Expression.Lambda<Func<TReferencedEntity, bool>>(containsExpression, entityParameter); 

     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 

     return result; 
    } 

Mais le test échoue à chaque fois, je suis passé la ligne Assert.AreEqual(expected, actual); à ceci: Assert.AreEqual(expected.ToString(), actual.ToString()); Je comprends pourquoi il échoue parce que quand vous regardez les résultats de la méthode ToString ils sont différents.

Assert.AreEqual failed. 
Expected:<referencedEntity => value(Shared.Infrastructure.Test.RemoteEntityRefLoaderTest+<>c__DisplayClass13).foreignKeys.Contains(Convert(referencedEntity.Id))>. 
Actual :<referencedEntity => value(System.Collections.Generic.List`1[System.Object]      )   .Contains(Convert(referencedEntity.Id))>. 

Je ne comprends pas pourquoi ... Est-ce que quelqu'un a des conseils généraux sur les expressions de tests unitaires et suggestions comment obtenir mon test spécifique de passer?

Merci ...

+0

mise à jour de la réponse. – Gishu

Répondre

13

Basé sur le code que vous avez posté,

  • la valeur attendue est un délégué/méthode anonyme. Le CLR fait un peu de magie derrière la scène pour ajouter une méthode à la volée. En cas d'anon. La méthode utilise certaines variables locales, le CLR crée une nouvelle classe avec des champs définis sur ces valeurs, avec la nouvelle méthode anon à l'intérieur (pour que la méthode puisse accéder aux valeurs var locales). Donc, c'est votre ..c_DisplayClass13, avec un compilateur donné un nom bizarre pour qu'il ne soit pas en conflit avec les méthodes définies par l'utilisateur.
  • La valeur réelle renvoyée par votre méthode est Expression<T>.

Et donc .. le contrôle d'égalité entre ces deux échoue. Vous devez comparer les éléments de la collection retournés par les deux. Je suggérerais donc ... de convertir les valeurs attendues et réelles en listes (ou une meilleure structure de données), puis d'invoquer l'une des affirmations de NUnit qui prend les paramètres de collection.

Mise à jour: Vous m'avez lu sur Expression Trees. +1 pour ça.
Je vais changer ma réponse - La comparaison des arbres d'Expression via hack-and-assert conduirait à un test fragile (par exemple si MS modifie la structure interne d'un arbre d'expression dans le futur)
Les arbres d'expression sont juste du code blocs (comme je l'ai découvert maintenant) qui évaluent à un résultat similaire à un Func<TInput,TResult) - donc mon test serait de donner les blocs de code attendus et réels la même entrée et voir si elles fournissent la même sortie. Donc, mon affirmation pour votre test serait

Assert.AreEqual(expected.Compile().Invoke(inputEntity), 
       actual.Compile().Invoke(inputEntity)); 
+0

Voulez-vous comparer chacun des nœuds dans chacune des expressions? – bytebender

+0

Je ne veux vraiment pas tester les collections Je veux tester les expressions ... – bytebender

+0

J'aime ça ... Je suis d'accord Si je compare les parties d'une expression et que Microsoft apporte quelques changements, je pourrais avoir un beaucoup de test échoué tout d'un coup. Je t'apprécie la stratégie. Merci! – bytebender