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

时间:2013-04-05 10:00:50

标签: c# linq lambda moq assert

我正试图在测试中断言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());

以上断言失败。字符串的预期表达式等于:

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()尝试比较这些是绝对错误的方法?替代?

1 个答案:

答案 0 :(得分: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

更好的做法是仅在客户端代码的接口上进行测试,而不需要测试任何有关如何查询存储库的知识。