Testowanie jednostek Aplikacja ASP.NET MVC5

Rozszerzam klasę ApplicationUser, dodając nową właściwość (jak pokazano w samouczku)Utwórz aplikację ASP.NET MVC 5 z Facebookiem i Google OAuth2 oraz OpenID Sign-on (C #))

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

Teraz chcę utworzyć test jednostkowy, aby sprawdzić, czy mój AccountController poprawnie zapisuje datę urodzenia.

Stworzyłem sklep użytkownika w pamięci o nazwie 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);
}

Metoda kontrolera.Register to standardowy kod generowany przez MVC5, ale dla celów odniesienia włączam go tutaj.

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

Kiedy dzwonię do rejestru, wywołuje SignInAsync, w którym wystąpi problem.

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

Na najniższej warstwie kod podstawowy zawiera ten smakołyk

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

To tutaj pojawia się korzeń problemu. To wywołanie GetOwinContext jest metodą rozszerzenia, której nie mogę wyszydzić i nie mogę zastąpić kodem pośredniczącym (chyba że oczywiście zmieniam kod podstawowy).

Po uruchomieniu tego testu otrzymuję wyjątek

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

W poprzednich wersjach zespół ASP.NET MVC pracował bardzo ciężko, aby kod był testowalny. Na pierwszy rzut oka wydaje się, że testowanie kontrolera konta nie będzie łatwe. Mam kilka wyborów.

mogę

Zmodyfikuj kod płyty kotła, aby nie wywoływał metody rozszerzenia i nie rozwiązywał tego problemu na tym poziomie

Ustaw rurociąg OWin do celów testowych

Unikaj pisania kodu testowego, który wymaga infrastruktury AuthN / AuthZ (nie jest to rozsądna opcja)

Nie jestem pewien, która droga jest lepsza. Każdy może to rozwiązać. Moje pytanie sprowadza się do najlepszej strategii.

Uwaga: Tak, wiem, że nie muszę testować kodu, którego nie napisałem. Infrastruktura UserManager, pod warunkiem, że MVC5 jest taką częścią infrastruktury, ALE jeśli chcę napisać testy, które weryfikują moje modyfikacje do ApplicationUser lub kodu, który weryfikuje zachowanie, które zależy od ról użytkownika, to muszę przetestować za pomocą UserManager.

questionAnswers(3)

yourAnswerToTheQuestion