![](/img/trans.png)
[英]FakeItEasy not verifying call for Full Framework SignalR test
[英]How to test for a Match with FakeItEasy on a predicate call?
我的代碼中有以下調用:
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
調用中設置參數匹配器的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
}
不過,總的來說,我會對這樣的測試發出警告 - 這對我來說似乎有點脆弱。 當然,您可能有充分的理由采用這種方法。 但是如果它適合你,另一種方法可能就是捕獲謂詞,然后通過讓它與已知的候選對象列表進行運行來查詢謂詞。 如果它按照你想要的方式過濾,那么它會通過。 這樣,如果某人以仍然有效的方式更改傳入的謂詞,可能通過將操作符切換到<
左邊的日期,測試仍然有效。 我只是把它作為另一種選擇。
對不起,我應該早點回答。 確實,Blair Conrad和我聊天,他幫助我理解如何更好地測試謂詞。 根據他的建議,我提出了以下解決方案。
在我的測試中,我創建了一個幫助器表達式提取器,如下所示:
private static string ExpressionExtractor(Expression<Func<CrossReferenceRelationshipEF, bool>> predicate)
{
var expression = ((BinaryExpression) ((LambdaExpression) ((MethodCallExpression) predicate.Body).Arguments[1]).Body);
var value = Expression.Lambda<Func<object>>(Expression.Convert(expression.Right, typeof (object))).Compile().Invoke();
return value.ToString();
}
然后在我的測試中,我可以這樣做我的斷言:
//Assert
A.CallTo(() => crossReferenceRelationshipRepositoryMock.SearchFor(A<Expression<Func<CrossReferenceRelationshipEF, bool>>>.That
.Matches(exp => ExpressionExtractor(exp) == "20/01/2014 14:06:55")))
.MustHaveHappened(Repeated.Exactly.Twice);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.