Pruebas Unitarias ASP.NET MVC5 App

Estoy extendiendo la clase ApplicationUser agregando una nueva propiedad (como se muestra en el tutorialCree una aplicación ASP.NET MVC 5 con Facebook y Google OAuth2 y OpenID Sign-on (C #))

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

Ahora quiero crear una prueba de unidad para verificar que mi AccountController está guardando correctamente la fecha de nacimiento.

He creado un almacén de usuarios en memoria llamado TestUserStore

[TestMethod]
public void Register()
{
    // Arrange
    var userManager = new UserManager<ApplicationUser>(new TestUserStore<ApplicationUser>());
    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);
}

El método controller.Register es un código repetitivo generado por MVC5, pero para fines de referencia lo incluyo aquí.

// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> 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);
}

Cuando llamo a Register, llama a SignInAsync, que es donde ocurrirá el problema.

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);
}

En la capa más baja, el código de plantilla incluye este tidbit

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

Aquí es donde se produce la raíz del problema. Esta llamada a GetOwinContext es un método de extensión que no puedo simular y no puedo reemplazar con un código auxiliar (a menos que, por supuesto, cambie el código del boilerplate).

Cuando ejecuto esta prueba obtengo una excepción

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.<SignInAsync>d__40.MoveNext() in AccountController.cs: line 336

En versiones anteriores, el equipo de ASP.NET MVC trabajó muy duro para hacer que el código fuera verificable. Parece ser que ahora probar un AccountController no será fácil. Tengo algunas opciones.

puedo

Modifique el código de la placa de la caldera para que no llame a un método de extensión y resuelva este problema a ese nivel

Configurar la tubería OWin para propósitos de prueba

Evite escribir el código de prueba que requiere la infraestructura AuthN / AuthZ (no es una opción razonable)

No estoy seguro de qué camino es mejor. Cualquiera de los dos podría resolver esto. Mi pregunta se reduce a cuál es la mejor estrategia.

Nota: Sí, sé que no necesito probar el código que no escribí. La infraestructura de UserManager provista MVC5 es una pieza de infraestructura PERO si quiero escribir pruebas que verifiquen mis modificaciones a ApplicationUser o código que verifique el comportamiento que depende de los roles de usuario, entonces debo probar usando UserManager.

Respuestas a la pregunta(3)

Su respuesta a la pregunta