2013-04-05 121 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