簡體   English   中英

如何在謂詞調用中測試與FakeItEasy的匹配?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM