C# 我如何设置(Moq 设置)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1052689/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I setup this (Moq Setup)
提问by chobo2
I want to test my part of code that returns the users password question. So I have made a mockup of the Membership provider using Moq.
我想测试我返回用户密码问题的代码部分。所以我使用 Moq 制作了会员资格提供者的模型。
I don't think I need to show you the actual code just the test part of it.
我认为我不需要向您展示实际的代码,而只是其中的测试部分。
// 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"));
So when I run this in Nunit I get this:
所以当我在 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
So I am guessing it is something because of the property that I am trying to access. I am not sure how to set it up. I am not very good with lambdas (and have not been able to find a tutorial on them yet) so I am not sure if I could some how arrange it differently to make it work.
所以我猜这是因为我试图访问的属性。我不知道如何设置它。我对 lambdas 不是很擅长(并且还没有找到关于它们的教程)所以我不确定我是否可以用不同的方式安排它以使其工作。
Or if I just totally missed the mark.
或者,如果我完全错过了标记。
采纳答案by eu-ge-ne
The answer is in exception message:
答案在异常消息中:
... Only property accesses are supported in intermediate invocations on a setup ...
... 设置的中间调用仅支持属性访问 ...
Try this:
尝试这个:
var user = new Mock<MemberShipUser>();
user.SetupGet(x => x.PasswordQuestion).Returns("Password");
membershipMock.Setup(m => m.GetUser("test", false)).Returns(user.Object);
回答by zvolkov
I suppose the intermediate invocation it refers to is this: m.GetUser("test", false)
since it's followed by .PasswordQuestion
. What it says is: you can't have a method used as an intermediate stub, only a property. This particular framework does seem to support intermediate stubs (i.e. constructs X.Y in the stub definition, note the dot) but most others don't.
我想它所指的中间调用是这样的:m.GetUser("test", false)
因为它后面跟着.PasswordQuestion
. 它说的是:您不能将方法用作中间存根,而只能用作属性。这个特定的框架似乎确实支持中间存根(即在存根定义中构造 XY,注意点)但大多数其他框架不支持。
Stubs are not magic, all they can do is intercept your calls and substitute the returned result with your provided value. In your case, your stub of GetUser needs to return a mock of user, with its PasswordQuestion stubbed away to return "Password".
存根不是魔法,它们所能做的就是拦截您的调用并将返回的结果替换为您提供的值。在您的情况下,您的 GetUser 存根需要返回一个模拟 user,其 PasswordQuestion 被存根以返回“密码”。
Another problem with your code is that you're mocking MembershipProvider directly. The way most of mocking framework work, if you mock an interface, they dynamically generate a class that implements it, and when you mock a class, they generate a class that inherits from it and overrides any virtual methods. However, if method is not virtual it can't override it, hence the mixed behavior you may observe. I suggest you see if there's an interface like IMembershipProvider and if yes, use that in your code instead of concrete class.
您的代码的另一个问题是您直接模拟 MembershipProvider。大多数模拟框架的工作方式是,如果你模拟一个接口,它们会动态生成一个实现它的类,当你模拟一个类时,它们会生成一个继承自它并覆盖任何虚拟方法的类。但是,如果方法不是虚拟的,则无法覆盖它,因此您可能会观察到混合行为。我建议你看看是否有像 IMembershipProvider 这样的接口,如果有,在你的代码中使用它而不是具体的类。