2011-07-11 22 views
13

我有工作執行的單位有(其中包括)以下方法:驗證方法調用與Lambda表達式 - 起訂量

T Single<T>(Expression<Func<T, bool>> expression) where T : class, new(); 

,我稱呼它,比如,像這樣:

var person = _uow.Single<Person>(p => p.FirstName == "Sergi"); 

如何驗證Single方法已被調用,參數爲FirstName == "Sergi"

我試過以下,但無濟於事:

// direct approach 
session.Verify(x => x.Single<Person>(p => p.FirstName == "Sergi")); 

// comparing expressions 
Expression<Func<Person, bool>> expression = p => p.FirstName == "Sergi"); 

session.Verify(x => x 
    .Single(It.Is<Expression<Func<Person, bool>>>(e => e == expression)); 

他們都導致如下因素的錯誤:

Expected invocation on the mock at least once, but was never performed

如何任何想法,可以做什麼? 我使用的是最新的Moq從的NuGet,版本4.0.10827.0

更新:一個具體的例子

我所看到的是,每當我用的是拉姆達Verify作品裏面的字符串文字。只要我比較變量,它就會失敗。案例分析:

// the verify 
someService.GetFromType(QuestionnaireType.Objective) 

session.Verify(x => x.Single<Questionnaire>(q => 
    q.Type == QuestionnaireType.Objective)); 


// QuestionnaireType.Objective is just a constant: 
const string Objective = "objective"; 


// the method where it's called (FAILS): 
public Questionnaire GetFromType(string type) 
{ 
    // this will fail the Verify 
    var questionnaire = _session 
     .Single<Questionnaire>(q => q.Type == type); 
} 

// the method where it's called (PASSES): 
public Questionnaire GetFromType(string type) 
{ 
    // this will pass the Verify 
    var questionnaire = _session 
     .Single<Questionnaire>(q => q.Type == QuestionnaireType.Objective); 
} 

怎麼來的Verify,只要我使用的方法參數的lambda表達式失敗?

寫這個測試的正確方法是什麼?

回答

11

直接的方法工作得很好,對我來說:

// direct approach 
session.Verify(x => x.Single<Person>(p => p.FirstName == "Sergi")); 

表達對象不等效的表達式返回true,這將失敗:

// comparing expressions 
Expression<Func<Person, bool>> expression = p => p.FirstName == "Sergi"); 

session.Verify(x => x 
    .Single(It.Is<Expression<Func<Person, bool>>>(e => e == expression)); 

要理解爲什麼,運行以下NUnit測試:

[Test] 
public void OperatorEqualEqualVerification() 
{ 
    Expression<Func<Person, bool>> expr1 = p => p.FirstName == "Sergi"; 
    Expression<Func<Person, bool>> expr2 = p => p.FirstName == "Sergi"; 
    Assert.IsTrue(expr1.ToString() == expr2.ToString()); 
    Assert.IsFalse(expr1.Equals(expr2)); 
    Assert.IsFalse(expr1 == expr2); 
    Assert.IsFalse(expr1.Body == expr2.Body); 
    Assert.IsFalse(expr1.Body.Equals(expr2.Body)); 
} 

並且如上面的測試表明, PRESSION身體也會失敗,但字符串比較有效,所以這個作品,以及:

// even their string representations! 
session.Verify(x => x 
    .Single(It.Is<Expression<Func<Person, bool>>>(e => 
     e.ToString() == expression.ToString())); 

而這裏的測試中多了一個風格,你可以添加到也適用阿森納:

[Test] 
public void CallbackVerification() 
{ 
    Expression<Func<Person, bool>> actualExpression = null; 
    var mockUow = new Mock<IUnitOfWork>(); 
    mockUow 
     .Setup(u => u.Single<Person>(It.IsAny<Expression<Func<Person, bool>>>())) 
     .Callback((Expression<Func<Person,bool>> x) => actualExpression = x); 
    var uow = mockUow.Object; 
    uow.Single<Person>(p => p.FirstName == "Sergi"); 

    Expression<Func<Person, bool>> expectedExpression = p => p.FirstName == "Sergi"; 

    Assert.AreEqual(expectedExpression.ToString(), actualExpression.ToString()); 
} 

正如你有很多測試用例不合格,你可能會遇到不同的問題。

UPDATE:根據您的更新,請考慮以下設置和表達式:

string normal_type = "NORMAL"; 
// PersonConstants is a static class with NORMAL_TYPE defined as follows: 
// public const string NORMAL_TYPE = "NORMAL"; 
Expression<Func<Person, bool>> expr1 = p => p.Type == normal_type; 
Expression<Func<Person, bool>> expr2 = p => p.Type == PersonConstants.NORMAL_TYPE; 

一個表達式引用包含方法的一個實例變量。另一個表示引用靜態類的const成員的表達式。這兩個表達式是不同的,不管在運行時可以賦給變量的值如何。但是,如果string normal_type更改爲const string normal_type,則表達式與表達式右側的每個參考a const再次相同。

+0

非常感謝您的回答。我根據新的呃...發現更新了我的問題,因爲缺乏更好的單詞。有任何想法嗎? –

+0

我已更新我的問題以解決可能是您的問題。這真的取決於QuestionnaireType.Objective的類型。我期望如果你使用'ToString()'這兩個表達式,你會發現它們是不同類型的。 –

+0

再次感謝,我想是有道理的。但是,那麼編寫這個測試的正確方法是什麼呢?我覺得在這種情況下,嘲笑是阻礙,而不是一個更清晰的代碼的工具... –

1

我還想分享另一種方法來比較參數表達式與預期表達式。我搜索的StackOverflow的 「如何比較表達式,」 我被帶到了這些文章:

我當時導致this Subversion repositorydb4o.net。在他們的其中一個項目名稱空間Db4objects.Db4o.Linq.Expressions中,它們包括一個名爲ExpressionEqualityComparer的類。我能夠從存儲庫中檢出這個項目,編譯,構建並創建一個DLL,以便在我自己的項目中使用。

隨着ExpressionEqualityComparer,你可以修改Verify調用類似以下內容:

session.Verify(x => x .Single(It.Is<Expression<Func<Person, bool>>>(e => new ExpressionEqualityComparer().Equals(e, expression))));

最終,ExpressionEqualityComparerToString()技術無論是在這種情況下返回true(與ToString最有可能的是速度更快 - 未經測試)。就我個人而言,我更喜歡比較器方法,因爲我覺得它比較自我記錄,並且更好地反映了您的設計意圖(比較表達式對象而不是它們的ToString輸出的字符串比較)。

說明:我仍然在尋找一個db4o.net許可證文件在這個項目中,但我還沒有修改代碼,包括版權聲明和(因爲該網頁是公開的)我假設現在已經足夠了...... ;-)