2009-06-27 133 views
11

我想測試返回用戶密碼問題的代碼部分。所以我用Moq做了一個會員提供商的模型。如何設置此(Moq設置)

我不認爲我需要告訴你實際的代碼只是它的測試部分。

// Arrange 
var membershipMock = new Mock<MembershipProvider>(); 
membershipMock.Setup(m => m.GetUser("test", false).PasswordQuestion).Returns("Password"); 
authentication.Authenticate.Provider = membershipMock.Object; 

// Act 
var actual = authentication.PasswordRecoveryStep1(It.IsAny<string>()); 

// Assert 
Assert.That(actual, Is.EqualTo("Password")); 

所以,當我運行這個在NUnit的,我得到這樣的:

Test.Controllers.AuthenticationControllerTest.Test_If_Password_Recovery_Setp1_Returns_Users_PasswordQuestion: 
System.NotSupportedException : Only property accesses are supported in intermediate invocations on a setup. Unsupported expression m.GetUser("test", False). 

at Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression m) 
at Moq.ExpressionVisitor.Visit(Expression exp) 
at Moq.Mock.AutoMockPropertiesVisitor.VisitMemberAccess(MemberExpression m) 
at Moq.ExpressionVisitor.Visit(Expression exp) 
at Moq.Mock.AutoMockPropertiesVisitor.SetupMocks(Expression expression) 
at Moq.Mock.GetInterceptor(LambdaExpression lambda, Mock mock) 
at Moq.Mock.<>c__DisplayClass15`2.<SetupGet>b__14() 
at Moq.PexProtector.Invoke[T](Func`1 function) 
at Moq.Mock.SetupGet[T1,TProperty](Mock mock, Expression`1 expression) 
at Moq.Mock.<>c__DisplayClass12`2.<Setup>b__11() 
at Moq.PexProtector.Invoke[T](Func`1 function) 
at Moq.Mock.Setup[T1,TResult](Mock mock, Expression`1 expression) 
at Moq.Mock`1.Setup[TResult](Expression`1 expression) 
at Test.Controllers.AuthenticationControllerTest.Test_If_Password_Recovery_Setp1_Returns_Users_PasswordQuestion() in D:\MvcApplication9\Test\Controllers\AuthenticationControllerTest.cs:line 186 

所以,我猜測這是因爲我想獲得的財產的東西。我不知道如何設置它。我對lambda表達不是很好(並且還沒能找到關於它們的教程),所以我不確定我是否可以通過不同的方式來安排它的工作方式。

或者如果我只是完全錯過了標記。

回答

13

答案是異常消息:

...唯一屬性的訪問都是在設置中間調用支持...

試試這個:

var user = new Mock<MemberShipUser>(); 
user.SetupGet(x => x.PasswordQuestion).Returns("Password"); 

membershipMock.Setup(m => m.GetUser("test", false)).Returns(user.Object); 
+1

雅我不知道那是什麼100%。這是否意味着只有一級屬性? 此外,你已經得到了過去的錯誤,但其他事情是錯的。 它似乎是不使用模擬對象,它試圖實際運行它對數據庫。 我把它設置成和我一樣的方式,我添加了模擬對象供這行使用: authentication.Authenticate.Provider = membershipMock.Object; – chobo2 2009-06-27 12:18:43

+0

好吧,我明白了。我完全忘記了當我寫這些東西時,我使用了諸如Membership.GetUser()之類的東西; 所以它從來沒有使用我的財產,要麼得到一個真正的提供者或模型提供者。 所以它現在有效。 但是我不明白它們之間的區別是什麼: 會員。的getUser(); //我之前使用的是什麼。 現在因爲我傳遞給它的供應商的事情(因爲我想如果我沒有我將無法使模擬對象呢?就像我能不能用會員資格,而不是Membership.Provider?) 我似乎得到一個不同的。 看起來一樣(稱爲getUser),但只有 – chobo2 2009-06-27 13:10:35

2

我想它所指的中間調用是這樣的:m.GetUser("test", false),因爲它後跟.PasswordQuestion。它說的是:你不能有一個方法用作中間存根,只有一個屬性。這個特定的框架看起來似乎支持中間存根(即在存根定義中構造X.Y,注意點),但大多數其他框沒有。

存根不是魔術,他們所能做的就是攔截你的調用並用你提供的值替換返回的結果。在你的情況下,你的存根的GetUser需要返回模擬用戶,它的PasswordQuestion被取消以返回「密碼」。

你的代碼的另一個問題是你直接嘲笑MembershipProvider。大多數模擬框架的工作方式,如果你模擬一個接口,他們動態地生成一個實現它的類,當你嘲笑一個類時,它們會生成一個繼承它的類並覆蓋任何虛擬方法。但是,如果方法不是虛擬的,它不能覆蓋它,因此可能會觀察到混合行爲。我建議你看看是否有像IMembershipProvider這樣的界面,如果是的話,在代碼中使用它,而不是具體的類。