2013-04-05 118 views
1

我試圖在測試中斷言2個Linq表達式。我使用Moq並在回調中捕獲被測方法內部調用的表達式。上述斷言失敗在C#中使用ToString幫助比較lambda表達式

var siteCode = "site1"; 
var namePattern = "role1"; 
Expression<Func<Role, bool>> expectedExpression = 
        t => (string.IsNullOrEmpty(siteCode) 
          || t.Name.StartsWith(siteCode + "_") 
          || t.Name == siteCode) 
          && t.Name.Contains(namePattern); 
Assert.AreEqual(expectedExpression.ToString(), actualExpression.ToString()); 

的:

Expression<Func<Role, bool>> actualExpression = null; 
roleRepositoryMock.Setup(t => t.Search(It.IsAny<Expression<Func<Role, bool>>>())) 
      .Callback((Expression<Func<Role, bool>> exp) => 
       { 
        actualExpression = exp; 
       }) 
      .Returns(new List<Role> { new Role { Name = "site1_code_role1", Description = "descr" }, new Role { Name = "site1_code" } }); 

我那麼這個未來的方式進行比較。預期表達爲字符串等於:

t => (((IsNullOrEmpty(value(BL.Tests.RolesServiceTests+<>c__DisplayClass6).siteCode) OrElse t.Name.StartsWith((value(BL.Tests.RolesServiceTests+<>c__DisplayClass6).siteCode + "_"))) OrElse (t.Name == value(BL.Tests.RolesServiceTests+<>c__DisplayClass6).siteCode)) AndAlso t.Name.Contains(value(BL.Tests.RolesServiceTests+<>c__DisplayClass6).namePattern)) 

而實際表達等於:

t => (((IsNullOrEmpty(value(BL.Services.RolesService+<>c__DisplayClass3).site) OrElse t.Name.StartsWith((value(BL.Services.RolesService+<>c__DisplayClass3).site + "_"))) OrElse (t.Name == value(BL.Services.RolesService+<>c__DisplayClass3).site)) AndAlso t.Name.Contains(value(BL.Services.RolesService+<>c__DisplayClass3).pattern)) 

的差異是在:

  • C_ DisplayClass6和c _DisplayClass3
  • BL.Services.RolesService和BL.Tests.RolesServiceTests(命名空間不同)

任何人都可以解釋或向正確的方向發送我爲什麼以及如何解決它? 也許這是一個絕對錯誤的方式來嘗試和通過ToString()比較這些?備擇方案?

回答

0

最好寫一些測試來驗證一段代碼的外部可觀察行爲,而不是耦合到實現細節。通過將表達式轉換爲字符串,您不僅可以將您的測試與您的確切表達式結合起來,還可以結合ToString方法的實現,該方法在未來的.NET版本中可能會發生變化。

更好的方法是斷言某些輸出狀態。它看起來像要驗證傳遞到您的存儲庫中的linq表達式將過濾出正確的Role集合。既然你已經可以通過回調捕捉表達式,爲什麼不用這個表達式來編寫一些測試呢?

假設RolePOCO,編寫測試調用與Role輸入的不同集合的表達式並聲明產生了正確的輸出應該是微不足道的。如果表達式是複雜的,你可能需要很多投入,但它會是這個樣子:

var roles = new List<Role> 
{ 
    new Role { Name = siteCode+"_role1" }, 
    new Role { Name = siteCode+"_role22" }, 
    new Role { Name = siteCode+"_role1324" }, 
}; 

Assert.AreEqual(2, roles.Where(actualExpression.Compile()).Count()); //test the number of roles returned is as expected 

更好的仍然是隻在客戶端代碼的接口進行測試,而無需怎樣的任何知識測試存儲庫被查詢。

+0

這是一個很好的建議。我想我試圖擺脫對象關係的建立(它是否是這種情況下的對象集合)來運行表達式。 – 2013-04-09 07:24:32