Модульное тестирование приложения ASP.NET MVC5

Расширение класса ApplicationUser путем добавления нового свойства (как показано в руководствеСоздайте приложение ASP.NET MVC 5 с Facebook и Google OAuth2 и OpenID Sign-on (C #))

public class ApplicationUser : IdentityUser
{
    public DateTime BirthDate { get; set; }
}

Теперь я хочу создать модульный тест, чтобы убедиться, что мой AccountController правильно сохраняет BirthDate.I '

мы создали пользовательское хранилище в памяти с именем TestUserStore

[TestMethod]
public void Register()
{
    // Arrange
    var userManager = new UserManager(new TestUserStore());
    var controller = new AccountController(userManager);

    // This will setup a fake HttpContext using Moq
    controller.SetFakeControllerContext();

    // Act
    var result =
        controller.Register(new RegisterViewModel
        {
            BirthDate = TestBirthDate,
            UserName = TestUser,
            Password = TestUserPassword,
            ConfirmPassword = TestUserPassword
        }).Result;

    // Assert
    Assert.IsNotNull(result);

    var addedUser = userManager.FindByName(TestUser);
    Assert.IsNotNull(addedUser);
    Assert.AreEqual(TestBirthDate, addedUser.BirthDate);
}

Метод controller.Register является стандартным кодом, сгенерированным MVC5, но для справочных целей I 'м, включая это здесь.

// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser() { UserName = model.UserName, BirthDate = model.BirthDate };
        var result = await UserManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            await SignInAsync(user, isPersistent: false);
            return RedirectToAction("Index", "Home");
        }
        else
        {
            AddErrors(result);
        }
    }

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

Когда я вызываю Register, он вызывает SignInAsync, где и происходит проблема.

private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
    var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
    AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}

На самом нижнем уровне, стандартный код включает в себя этот лакомый кусочек

private IAuthenticationManager AuthenticationManager
{
    get
    {
        return HttpContext.GetOwinContext().Authentication;
    }
}

Вот где возникает корень проблемы. Этот вызов GetOwinContext является методом расширения, который я не могу смутить и не могу заменить заглушкой (если, конечно, я не изменю шаблонный код).

Когда я запускаю этот тест, я получаю исключение

Test method MVCLabMigration.Tests.Controllers.AccountControllerTest.Register threw exception: 
System.AggregateException: One or more errors occurred. ---> System.NullReferenceException: Object reference not set to an instance of an object.
at System.Web.HttpContextBaseExtensions.GetOwinEnvironment(HttpContextBase context)
at System.Web.HttpContextBaseExtensions.GetOwinContext(HttpContextBase context)
at MVCLabMigration.Controllers.AccountController.get_AuthenticationManager() in AccountController.cs: line 330
at MVCLabMigration.Controllers.AccountController.d__40.MoveNext() in AccountController.cs: line 336

В предыдущих выпусках команда ASP.NET MVC очень много работала, чтобы сделать код тестируемым. На первый взгляд кажется, что сейчас тестирование AccountController не будет легким. У меня есть выбор.

Я могу

Измените код пластины котла так, чтобы он невызвать метод расширения и решить эту проблему на этом уровне

Настройте конвейер OWin для тестирования

Избегайте написания тестового кода, который требует инфраструктуры AuthN / AuthZ (не разумный вариант)

Я не уверен, какая дорога лучше. Либо кто-то может решить это. Мой вопрос сводится к тому, какая стратегия является лучшей.

Примечание: да, я знаю, что нене нужно тестировать код, который я не сделалт писать. Инфраструктура UserManager, предоставляемая MVC5, является такой частью инфраструктуры, НО, если я хочу написать тесты, которые проверяют мои модификации ApplicationUser или код, который проверяет поведение, зависящее от ролей пользователя, тогда я должен протестировать с помощью UserManager.

Ответы на вопрос(3)

Ваш ответ на вопрос