2009-05-04 40 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()); 
    } 

當我終於得到了「BuildForeignKeysContainsPredicate」的方法工作,我永遠無法得到德測試通...這裏是方法:

/// <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 2009-05-05 06:14:21

回答

13

根據您所發佈的代碼,

  • 期望值是匿名委託/方法。 CLR在幕後做了一些魔術,以便隨時添加一種方法。在anon的情況下。方法使用某些局部變量,CLR創建一個新的類,其中的字段設置爲這些值,其中新的匿名方法(以便該方法可以訪問本地var值)。所以這就是你的..c_DisplayClass13,編譯器給出了一個奇怪的名字,以便它不會與用戶定義的方法衝突。
  • 您的方法返回的實際值爲Expression<T>

因此,這兩者之間的相等性檢查失敗。您需要比較兩者返回的集合的元素。所以我建議..將預期值和實際值轉換爲列表(或更好的數據結構),然後調用採用集合參數的NUnit斷言之一。

更新:你讓我讀了Expression Trees。 +1。
我將改變我的答案 - 通過hack-and-assert比較表達式樹會導致脆弱的測試(例如,如果MS將來改變表達式樹的內部結構)
表達式樹只是代碼塊(現在我發現了)評估結果類似於Func<TInput,TResult) - 所以我的測試是給予預期的和實際的代碼塊相同的輸入並查看它們是否提供相同的輸出。 所以我斷言你的測試將是

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

你是說比較每個表達式中的每個節點嗎? – bytebender 2009-05-04 19:06:23