1

我正在尝试在测试中断言 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_DisplayClass6c_DisplayClass3
  • BL.Services.RolesService 和 BL.Tests.RolesServiceTests(命名空间不同)

任何人都可以解释或向我发送正确的方向为什么以及如何解决它?也许尝试通过 ToString() 比较这些是绝对错误的方法?备择方案?

4

1 回答 1

0

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

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

假设Role是一个POCORole ,编写调用具有不同输入集合的表达式并断言产生正确输出的测试应该是微不足道的。如果表达式很复杂,您可能需要许多输入,但它看起来像这样:

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

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

于 2013-04-06T12:11:19.910 回答