c# - 如何在谓词调用中测试与 FakeItEasy 的匹配?

标签 c# lambda predicate fakeiteasy

我的代码中有以下调用:

var dbResults = new List<CrossReferenceRelationshipEF>();
dbResults = dateTimeFilter == null
    ? new List<CrossReferenceRelationshipEF>(
        CrossReferenceRelationshipRepository.GetAll()
                .ToList().OrderBy(crr => crr.ToPartner))
    : new List<CrossReferenceRelationshipEF>(
        CrossReferenceRelationshipRepository.SearchFor(
            crr => crr.HistoricEntries
                .Any(he => he.ModifiedDatetime > dateTimeFilter))
                .ToList().OrderBy(crr => crr.ToPartner));

我正在尝试使用 FakeItEasy 来验证当 dateTimeFilter 有一个值时,SearchFor(…) 在我的存储库中被调用并具有正确的函数。

所以我的测试看起来像这样:

A.CallTo(() => crossReferenceRelationshipRepositoryMock.SearchFor(A<Expression<Func<CrossReferenceRelationshipEF,bool>>>.That
    .Matches(exp => Expression.Lambda<Func<DateTime>>(((BinaryExpression)exp.Body).Right).Compile().Invoke() == filterByDate)))
    .MustHaveHappened(Repeated.Exactly.Once);

这是不正确的。 有什么方法可以测试我是否使用正确的表达式调用 SearchFor(...)

crr => crr.HistoricEntries.Any(he => he.ModifiedDatetime > dateTimeFilter)

传递给 SearchFor(…) 的实际值是 DateTime.MinValue 所以我将断言更改为:

A.CallTo(() => crossReferenceRelationshipRepositoryMock.SearchFor(A<Expression<Func<CrossReferenceRelationshipEF, bool>>>.That
    .Matches(exp => Expression.Lambda<Func<DateTime>>(((BinaryExpression)exp.Body).Right).Compile().Invoke() == DateTime.MinValue)))
    .MustHaveHappened(Repeated.Exactly.Once);

这是失败的,我得到的异常是

System.InvalidCastException:
  Unable to cast object of type 'System.Linq.Expressions.MethodCallExpressionN'
  to type 'System.Linq.Expressions.BinaryExpression'.

我不确定我做错了什么......

最佳答案

披露 - VasilisP 和我昨天聊了聊这个。

在某种程度上,这并不是真正的 FakeItEasy 问题。您在 A.CallTo 中设置参数匹配器的方法通话正常。问题是您提供的用于匹配谓词的 lambda 不起作用。这将问题归结为“我如何判断一个表达式是否是我想要的?”。

还有其他的StackOverflow问题会问类似这样的问题,比如

其中一种方法可能适合您。

但是,您看到的异常的直接原因是传入的谓词不是 BinaryExpression , 这是一个 MethodCallExpression .您可以考虑更改您的测试以说明这一点并遵循它引导您的路径。

我填写了一些类定义并将匹配器提取到此函数,并且至少能够在谓词中找到 dateArgument:

public bool IsPredicateGood(Expression<Func<CrossReferenceRelationshipEF, bool>> predicate)
{
    var typedPredicate = (MethodCallExpression) predicate.Body;
    var innerPredicate = ((LambdaExpression)typedPredicate.Arguments[1]).Body;
    var dateArgument = ((BinaryExpression) innerPredicate).Right;
    return dateArgument != null; // not a real test yet, but you could adapt
}

不过,总的来说,我会警告不要像这样进行测试 - 它对我来说似乎有点脆弱。当然,您可能有充分的理由采用这种方法。但是,如果它适合您,另一种方法可能是只捕获谓词,然后通过让它针对已知的候选对象列表运行来询问它。如果它按照您想要的方式进行过滤,那么它就会通过。 这样,如果有人以仍然有效的方式更改传入的谓词,可能是通过将运算符切换为 <。日期在左边,测试仍然有效。我只是把它作为另一种选择。

关于c# - 如何在谓词调用中测试与 FakeItEasy 的匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21437044/

相关文章:

c# - 编码/解码文本框

python - 为什么我在 pandas 的 apply/assign 函数中得到一个系列?想要使用每个值来查找字典

java - 如何在运行时过滤 java 对象列表,其中我要过滤的变量事先未知?

java - 在参数中给定多个条件时过滤流

c# - 使用 tidymanaged 格式化 HTML

c# - 在 NET Core 中调用从 C++ 项目构建的 .dll 时出现 BadImageFormatException

c# - 为什么System.ServiceModel.Dispatcher需要全限定才能编译

java - Lambda 捕获与非捕获

java - 将 lambda 分配给功能接口(interface)变量 : inherited abstract method must be implemented. 时出错,为什么?

iphone - 在 Core Data 中的文件夹结构中搜索