2009-05-04 20 views
9

ich vor kurzem einen Ausdrucksbaum aufbauen müssen, so schrieb ich eine Testmethode, wie so ...Unit Testing Expression Trees

/// <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()); 
    } 

Als ich endlich die „BuildForeignKeysContainsPredicate“ Methode bekam ich nie arbeiten teh Test bekommen könnte passieren ... Hier ist die Methode:

/// <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; 
    } 

Aber der Test jedes Mal versagt, schaltete ich die Linie Assert.AreEqual(expected, actual); dazu: Assert.AreEqual(expected.ToString(), actual.ToString()); ich verstehe, warum es versagt, denn wenn man die Ergebnisse der ToString-Methode zu buchen Sie sind anders.

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))>. 

Ich verstehe einfach nicht, warum ... Hat jemand haben allgemeine Tipps auf Unit-Tests Ausdrücke und Vorschläge, wie meine speziellen Test zu bestehen zu bekommen?

Dank ...

+0

aktualisierte Antwort. – Gishu

Antwort

13

Basierend auf dem Code, den Sie, gepostet haben

  • der erwartete Wert ist eine anonyme Delegat/Methode. Die CLR zaubert hinter die Kulissen, um spontan eine Methode hinzuzufügen. Für den Fall, dass der Anon. Wenn die Methode bestimmte lokale Variablen verwendet, erstellt die CLR eine neue Klasse mit Feldern, die auf diese Werte gesetzt sind, wobei die neue anon-Methode darin enthalten ist (damit die Methode auf die lokalen var-Werte zugreifen kann). Das ist also deine ..c_DisplayClass13, mit einem Compiler, der einen seltsamen Namen hat, so dass er nicht mit benutzerdefinierten Methoden kollidiert.
  • Der tatsächliche von Ihrer Methode zurückgegebene Wert ist Expression<T>.

Und daher .. die Gleichheitsprüfung zwischen diesen beiden fehlschlägt. Sie müssen die Elemente der Sammlung vergleichen, die von beiden zurückgegeben werden. Ich würde also vorschlagen, ... die erwarteten und tatsächlichen Werte in Listen (oder eine bessere Datenstruktur) zu konvertieren und dann einen der NUnit-Ausdrücke aufzurufen, die Collection-Parameter verwenden.

Aktualisieren: Sie haben mich auf Expression Trees lesen. +1 dafür.
Ich werde meine Antwort ändern - Vergleichen der Ausdruck Bäume über Hack-and-Assert würde zu einem fragilen Test führen (zB wenn MS die interne Struktur eines Ausdrucksbaums in der Zukunft ändert)
Ausdruck Bäume sind nur Code Blöcke (wie ich jetzt herausgefunden habe), die zu einem Ergebnis ähnlich einem Func<TInput,TResult) auswerten - so würde mein Test sein, den erwarteten und tatsächlichen Code zu geben, der die gleiche Eingabe blockiert und sieht, ob sie die gleiche Ausgabe liefern. Also meine Behauptung für Ihren Test wäre

+0

Sie sagen, vergleichen Sie jeden der Knoten in jedem der Ausdrücke? – bytebender

+0

Ich möchte wirklich nicht die Sammlungen testen Ich möchte die Ausdrücke zu testen ... – bytebender

+0

Ich mag es ... Ich stimme zu Wenn ich die Teile und Teile eines Ausdrucks zu vergleichen und Microsoft einige Änderungen macht, könnte ich eine haben Viele versagende Tests auf einmal. Ich mag dich Strategie. Vielen Dank! – bytebender