2009-06-27 147 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这样的界面,如果是的话,在代码中使用它,而不是具体的类。