Как мне это настроить (Moq Setup) - PullRequest
12 голосов
/ 27 июня 2009

Я хочу проверить свою часть кода, которая возвращает вопрос о пароле пользователя. Итак, я сделал макет поставщика Членства, используя 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

Так что я предполагаю, что это что-то из-за свойства, к которому я пытаюсь получить доступ. Я не уверен, как это настроить. Я не очень хорошо разбираюсь с лямбдами (и пока не смог найти для них учебное пособие), поэтому я не уверен, смогу ли я как-то устроить его по-другому, чтобы он работал.

Или если я просто пропустил отметку.

Ответы [ 2 ]

13 голосов
/ 27 июня 2009

Ответ в сообщении об исключении:

... При промежуточных вызовах в настройке поддерживаются только обращения к свойствам ...

Попробуйте это:

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

membershipMock.Setup(m => m.GetUser("test", false)).Returns(user.Object);
2 голосов
/ 27 июня 2009

Полагаю, промежуточный вызов, на который он ссылается, таков: m.GetUser("test", false), поскольку за ним следует .PasswordQuestion. Это говорит о том, что нельзя использовать метод в качестве промежуточной заглушки, только свойство. Эта конкретная структура, кажется, поддерживает промежуточные заглушки (т.е. создает X.Y в определении заглушки, обратите внимание на точку), но большинство других не поддерживают.

Заглушки не волшебны, все, что они могут сделать, это перехватить ваши звонки и заменить возвращаемый результат указанным вами значением. В вашем случае ваша заглушка GetUser должна вернуть макет пользователя , а его PasswordQuestion заглушен, чтобы вернуть "Password".

Еще одна проблема с вашим кодом заключается в том, что вы издеваетесь над MembershipProvider напрямую. Как работает большинство фальшивых фреймворков: если вы имитируете интерфейс, они динамически генерируют класс, который его реализует, а когда вы имитируете класс, они генерируют класс, который наследует его и переопределяет любые виртуальные методы. Однако, если метод не является виртуальным, он не может переопределить его, поэтому вы можете наблюдать смешанное поведение. Я предлагаю вам посмотреть, есть ли такой интерфейс, как IMembershipProvider, и если да, используйте его в своем коде вместо конкретного класса.

...