在ToString的帮助下比较c#中的lambda表达式

本文关键字:中的 lambda 表达式 比较 ToString 帮助 | 更新日期: 2023-09-27 18:07:28

我试图在测试中断言2个Linq表达式。我正在使用Moq,并在回调时捕获在测试方法内调用的表达式。

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" } });

然后我以另一种方式比较:

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

上面的Assert失败。期望的字符串表达式等于:

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()?选择呢?

在ToString的帮助下比较c#中的lambda表达式

最好编写测试来验证一段代码的外部可观察行为,而不耦合到实现细节。通过将表达式转换为字符串,您不仅将测试与您的精确表达式耦合,而且还将测试与ToString方法的实现耦合,这可能会在未来的。net版本中发生变化。

更好的方法是断言一些输出状态。看起来您想要验证传递到存储库的linq表达式是否能够过滤出正确的Role集合。既然已经可以通过回调捕获表达式,为什么不针对该表达式编写一些测试呢?

假设Role是一个POCO,编写使用不同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

更好的方法是只在客户端代码的接口上进行测试,而不让测试知道如何查询存储库。