2009-05-04 12 views
9

recientemente que necesito para construir un árbol de expresión por lo que escribió un método de prueba como tal ...Unidad de árboles de expresión Pruebas

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

Cuando por fin llegué el método "BuildForeignKeysContainsPredicate" de trabajo que nunca podría conseguir teh a prueba pasar ... Aquí está el método:

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

Pero la prueba falla cada vez, cambié la línea Assert.AreEqual(expected, actual); a esto: Assert.AreEqual(expected.ToString(), actual.ToString()); entiendo por qué está fallando porque cuando nos fijamos en los resultados del método ToString ellos son diferentes.

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

Simplemente no entiendo por qué ... ¿Alguien tiene consejos generales sobre expresiones pruebas unitarias y sugerencias de cómo conseguir mi prueba específica a pasar?

Gracias ...

+0

respuesta actualizada. – Gishu

Respuesta

13

Basado en el código que has enviado,

  • el valor esperado es un delegado/método anónimo. El CLR hace algo de magia detrás de la escena para agregar un método sobre la marcha. En caso de que el anon. método utiliza ciertas variables locales, el CLR crea una nueva clase con campos establecidos en estos valores, con el nuevo método anon dentro de él (para que el método pueda acceder a los valores de var locales). Así que esa es tu ..c_DisplayClass13, con un nombre extraño dado a un compilador para que no entre en conflicto con los métodos definidos por el usuario.
  • El valor real devuelto por su método es Expression<T>.

Y, por tanto, la comprobación de igualdad entre estos dos falla. Necesita comparar los elementos de la colección devueltos por ambos. Así que sugeriría ... convertir los valores esperados y los reales en Listas (o una mejor estructura de datos) y luego invocar uno de los asertos de NUnit que toman los parámetros de la colección.

Actualización: Me tienes que leer en Expression Trees. +1 por eso.
Voy a cambiar mi respuesta: comparar los árboles de Expression mediante hack-and-assert daría lugar a una prueba frágil (por ejemplo, si MS modifica la estructura interna de un árbol de expresiones en el futuro)
Los árboles de expresiones son solo código bloques (como descubrí ahora) que evalúan a un resultado similar a Func<TInput,TResult) - por lo que mi prueba sería dar a los bloques de código esperados y reales la misma entrada y ver si ofrecen el mismo resultado. Así que mi afirmación para su prueba sería

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

¿Estás diciendo que comparas cada uno de los Nodos en cada una de las expresiones? – bytebender

+0

Realmente no quiero probar las colecciones Quiero probar las expresiones ... – bytebender

+0

Me gusta ... Acepto Si me pongo a comparar las partes y piezas de una expresión y Microsoft hace algunos cambios podría tener una Gran cantidad de pruebas fallidas, de repente. Me gusta tu estrategia. ¡Gracias! – bytebender

Cuestiones relacionadas