2009-05-04 12 views
9

Recentemente ho bisogno di costruire un albero di espressione così ho scritto un metodo di prova in questo modo ...Unità Alberi Testing Espressione

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

Quando finalmente ho avuto il metodo "BuildForeignKeysContainsPredicate" lavorare ho mai potuto ottenere teh test per passano ... Ecco il metodo:

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

Ma il test fallisce ogni volta, ho cambiato la linea Assert.AreEqual(expected, actual); a questo: Assert.AreEqual(expected.ToString(), actual.ToString()); capisco il motivo per cui sta venendo a mancare, perché quando si guardano i risultati del metodo ToStringsono diversi.

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

Io proprio non capisco perché ... non uno ha consigli generali su espressioni unit test e suggerimenti su come ottenere il mio test specifico di passare?

Grazie ...

+0

risposta aggiornata. – Gishu

risposta

13

In base al codice che hai postato,

  • il valore atteso è un delegato/metodo anonimo. Il CLR fa un po 'di magia dietro la scena per aggiungere un metodo al volo. Nel caso in cui l'anon. il metodo utilizza determinate variabili locali, il CLR crea una nuova classe con i campi impostati su questi valori, con il nuovo metodo anon al suo interno (in modo che il metodo possa accedere ai valori var locali). Quindi questo è il tuo ..c_DisplayClass13, con un compilatore con un nome strano in modo che non si scontri con i metodi definiti dall'utente.
  • Il valore effettivo restituito dal metodo è Expression<T>.

E quindi ... il controllo di uguaglianza tra questi due fallisce. È necessario confrontare gli elementi della raccolta restituiti da entrambi. Quindi suggerirei di convertire sia i valori attesi che quelli effettivi in ​​Liste (o una struttura dati migliore) e quindi richiamare uno degli asserzioni di NUnit che prendono i parametri di raccolta.

Aggiornamento: Mi hai fatto leggere su Expression Trees. +1 per quello.
Ho intenzione di cambiare la mia risposta - Il confronto degli alberi di espressione tramite hack-and-assert porterebbe a un test fragile (ad esempio se MS modifica la struttura interna di un albero di espressioni in futuro)
Gli alberi di espressione sono solo codice blocchi (come ho scoperto ora) che valutano un risultato simile a uno Func<TInput,TResult) - quindi il mio test sarebbe quello di dare i blocchi di codice previsti e reali lo stesso input e vedere se forniscono lo stesso output. Quindi la mia asserzione per il test sarebbe

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

Stai dicendo di confrontare ciascuno dei nodi in ciascuna delle espressioni? – bytebender

+0

Davvero non voglio testare le collezioni che voglio testare le espressioni ... – bytebender

+0

Mi piace ... Sono d'accordo Se riesco a confrontare le parti e le parti di un'espressione e Microsoft apporta alcune modifiche potrei avere un molti test falliti all'improvviso. Mi piace la tua strategia. Grazie! – bytebender

Problemi correlati