12

我想测试我返回用户密码问题的代码部分。因此,我使用 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

所以我猜这是因为我试图访问的属性。我不知道如何设置它。我对 lambdas 不是很好(并且还没有找到关于它们的教程),所以我不确定我是否可以通过不同的方式安排它以使其工作。

或者,如果我完全错过了目标。

4

2 回答 2

14

答案在异常消息中:

...在设置的中间调用中仅支持属性访问...

试试这个:

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

membershipMock.Setup(m => m.GetUser("test", false)).Returns(user.Object);
于 2009-06-27T11:58:26.010 回答
2

我想它所指的中间调用是这样m.GetUser("test", false)的:因为它后面跟着.PasswordQuestion. 它说的是:您不能将方法用作中间存根,而只能用作属性。这个特定的框架似乎支持中间存根(即在存根定义中构造 XY,注意点),但大多数其他框架不支持。

存根并不神奇,它们所能做的就是拦截您的调用并将返回的结果替换为您提供的值。在您的情况下,您的 GetUser 存根需要返回一个模拟 user,并将其 PasswordQuestion 存根以返回“密码”。

您的代码的另一个问题是您直接模拟 MembershipProvider。大多数模拟框架的工作方式是,如果你模拟一个接口,它们会动态生成一个实现它的类,当你模拟一个类时,它们会生成一个继承自它并覆盖任何虚拟方法的类。但是,如果方法不是虚拟的,则无法覆盖它,因此您可能会观察到混合行为。我建议你看看是否有像 IMembershipProvider 这样的接口,如果有,在你的代码中使用它而不是具体的类。

于 2009-06-27T12:24:17.753 回答