2009-05-04 5 views
9

...ユニットテストの式ツリー

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

私はへのtehのテストを入手することができませんでした合格...ここでの方法である:

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

しかし、テストは毎回失敗し、私はラインこれにAssert.AreEqual(expected, actual); 切り替え:Assert.AreEqual(expected.ToString(), actual.ToString());それが失敗している理由を私は理解しますが、ToStringメソッドの結果を見ると理由それらは違う。

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

私はちょうど理由を理解していません...誰かが単体テストの表現に関する一般的なヒントを持ち、特定のテストをパスする方法を提案していますか?

おかげで...あなたが投稿したコードに基づいて

+0

更新答えになるでしょう。 – Gishu

答えて

13

  • 期待値は、匿名デリゲート/方法です。 CLRは、場面の背後にいくつかの魔法をかけて、その場でメソッドを追加します。 anonの場合。メソッドが特定のローカル変数を使用する場合、CLRは、これらの値に設定されたフィールドを持つ新しいクラスを作成し、内部に新しいanonメソッドを追加します(メソッドはローカルのvar値にアクセスできます)。それはあなたの..c_DisplayClass13です。コンパイラは奇妙な名前を与えられ、ユーザ定義のメソッドと衝突しません。
  • メソッドによって返される実際の値はExpression<T>です。

したがって、これら2つの間の平等チェックは失敗します。両方から返されたコレクションの要素を比較する必要があります。だから、私は示唆したい.. Lists(またはより良いデータ構造)に期待値と実際の値を変換し、コレクションパラメータを取るNUnitのアサートの1つを呼び出します。

更新:私はExpression Treesで読んでください。それに対して+1。
私の答えを変えようとしています - ハックアンドアサートによる式ツリーの比較は、壊れやすいテストにつながります(例えば、MSが将来、エクスプレッションツリーの内部構造を変更する場合)
エクスプレッションツリーは単なるコードですFunc<TInput,TResult)に似た結果に評価されるブロック(私が今見出したように) - 私のテストは、期待された実際のコードブロックに同じ入力を与え、それらが同じ出力を出すかどうかを見ることです。 あなたのテストの私の主張は、

+0

各式の各ノードを比較していますか? – bytebender

+0

私はコレクションをテストしたくありません。私は式をテストしたいと思っています... – bytebender

+0

私はそれが好きです...私は同意します。表現の部分と部分を比較すると、Microsoftはいくつかの変更を加えます突然突然の失敗テストの多く。私はあなたの戦略が好きです。ありがとう! – bytebender