我的代码中有以下调用:
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问题会问类似这样的问题,比如
- Most efficient way to test equality of lambda expressions ,
- How to check if two Expression<Func<T, bool>> are the same , 和
- How to test expressions equality
其中一种方法可能适合您。
但是,您看到的异常的直接原因是传入的谓词不是 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/