Модульные тесты ASP.NET MVC 3 для Membership.CreateUser всегда возвращают ошибку MembershipCreateStatus - PullRequest
2 голосов
/ 31 мая 2011

Я пытаюсь написать модульный тест для создания нового пользователя и проверки того, что происходит желаемое перенаправление. Вот мое Register действие, которое в значительной степени является готовым кодом из шаблона VS:

[HttpPost]
public ActionResult Register(RegisterModel model)
{
    if (ModelState.IsValid)
    {
        // Attempt to register the user
        MembershipCreateStatus createStatus;
        Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus);

        if (createStatus == MembershipCreateStatus.Success)
        {
            FormsAuthentication.SetAuthCookie(model.UserName, false /* createPersistentCookie */);
            return RedirectToAction("Index", "Home");
        }
        else
        {
            ModelState.AddModelError(String.Empty, ErrorCodeToString(createStatus));
        }
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

И вот мой тест с использованием Moq. Независимо от того, что я установил, я всегда получаю сообщение об ошибке по умолчанию MembershipCreateStatus. Например:

Предоставленный пароль недействителен. Пожалуйста, введите правильный пароль

или

Предоставлен неверный ответ для получения пароля

Я пытался изменить метод CreateUser так, чтобы он вызывал только имя пользователя, пароль и перегрузку электронной почты, но это не имеет значения. Как будто где-то есть проверка, которая применяет политику паролей.

public void RegisterPost_WithAuthenticatedUser_RedirectsToHomeControllerIfSuccessful()
{
    // Arrange
    var accountController = new AccountController();
    var mockContext = GetMockRequestContext();

    ControllerContext controllerContext = new ControllerContext(mockContext.Object, accountController);
    accountController.ControllerContext = controllerContext;

    RegisterModel registerModel = new RegisterModel() { UserName = "someone", Email = "someone@example.com", Password = "user", ConfirmPassword = "password" };

    // Act
    var result = accountController.Register(registerModel);

    // Assert
    Assert.That(result.RouteData.Values["Controller"], Is.EqualTo("Home"));
    Assert.That(result.RouteData.Values["Action"], Is.EqualTo("Index"));
}

Может кто-нибудь сказать мне, что здесь происходит?

Ответы [ 2 ]

11 голосов
/ 31 мая 2011

Проблема статического класса / метода снова возникает!

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

Что вам нужно сделать, это сделать эту зависимость явной. Сделайте это, представив интерфейс, который моделирует взаимодействие, требуемое с поставщиком членства (скажем, называется IMembershipService).

Создайте реализацию по умолчанию, которая просто делегирует существующим статическим методам, таким как Membership.CreateUser(). В вашем контроллере требуется экземпляр этого интерфейса в конструкторе (или создайте экземпляр реализации по умолчанию в конструкторе по умолчанию, если необходимо - не предпочтительный вариант, но ...)

Затем в своем тесте создайте макет этого интерфейса и установите требуемые ожидания, передайте этот макет вашему контроллеру и убедитесь, что он выполняет то, что вы ожидаете.

Если вы не используете макет, то вы будете создавать новых пользователей в вашей базе данных каждый раз, когда будет выполняться тест. это может быть хорошо, если вы каждый раз сбрасываете свою базу данных, но использование макета проще и быстрее в долгосрочной перспективе, хотя это требует немного больше усилий для настройки, так как вам нужно создать контроллер конструктора no null arg и ввести несколько интерфейсов для разбиения неявных зависимостей на явные зависимости.

3 голосов
/ 31 мая 2011

Membership.CreateUser - это просто статическая оболочка, задача фактически делегирована сконфигурированной реализации MembershipProvider.

Если вы не настроили поставщика членства, используется поставщик по умолчанию, настроенный в machine.config. Для .NET v4.0 на моей машине это выглядит так:

<membership>
   <providers>
    <add name="AspNetSqlMembershipProvider" 
             type="System.Web.Security.SqlMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" 
             connectionStringName="LocalSqlServer" 
             enablePasswordRetrieval="false" 
             enablePasswordReset="true" 
             requiresQuestionAndAnswer="true" 
             applicationName="/" 
             requiresUniqueEmail="false" 
             passwordFormat="Hashed" 
             maxInvalidPasswordAttempts="5" 
             minRequiredPasswordLength="7" 
             minRequiredNonalphanumericCharacters="1" 
             passwordAttemptWindow="10" 
             passwordStrengthRegularExpression=""/>
   </providers>
</membership>

Обратите внимание на атрибуты requiresQuestionAndAnswer и minRequiredPasswordLength, которые применяют определенные правила по умолчанию.

Полагаю, вы настраиваете свой собственный MembershipProvider в веб-приложении, но, скорее всего, вы забыли принять эту конфигурацию для модульного теста (в app.config тестового проекта), и, следовательно, эти настройки по умолчанию вступают в силу.

...