2016-07-26 13 views
5

Próbuję badanej jednostki prostą metodę jak Login to w moim AccountController podstawie this testu z MusiStore przykład.Jak prawidłowo naśladować IAuthenticationHandler podczas testów jednostkowych kontroler ASP.NET Rdzeń

// POST: /Account/Login 
[HttpPost] 
[AllowAnonymous] 
[ValidateAntiForgeryToken] 
public async Task<IActionResult> Login(LoginArgumentsModel model) 
{ 
    if (!ModelState.IsValid) 
    { 
     return BadRequest(); 
    } 
    var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: false); 
    if (result.Succeeded) 
    { 
     return Ok(); 
    } 
return StatusCode(422); // Unprocessable Entity 
} 

Do tego trzeba użyć zarówno UserManager i SignInManager który ostatecznie zmusza mnie do korzystania pisać namiastkę IAuthenticationHandler do stosowania w HttpAuthenticationFeature. W końcu testu okaże się tak:

public class AccountControllerTestsFixture : IDisposable 
{ 
    public IServiceProvider BuildServiceProvider(IAuthenticationHandler handler) 
    { 
     var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider(); 

     var services = new ServiceCollection(); 
     services.AddOptions(); 
     services.AddDbContext<ApplicationDbContext>(b => b.UseInMemoryDatabase().UseInternalServiceProvider(efServiceProvider)); 

     services.AddIdentity<ApplicationUser, IdentityRole>(o => 
     { 
      o.Password.RequireDigit = false; 
      o.Password.RequireLowercase = false; 
      o.Password.RequireUppercase = false; 
      o.Password.RequireNonAlphanumeric = false; 
      o.Password.RequiredLength = 3; 
     }).AddEntityFrameworkStores<ApplicationDbContext>(); 

      // IHttpContextAccessor is required for SignInManager, and UserManager 
     var context = new DefaultHttpContext(); 

     context.Features.Set<IHttpAuthenticationFeature>(new HttpAuthenticationFeature { Handler = handler }); 

     services.AddSingleton<IHttpContextAccessor>(new HttpContextAccessor() 
     { 
      HttpContext = context 
     }); 

     return services.BuildServiceProvider(); 
    } 

    public Mock<IAuthenticationHandler> MockSignInHandler() 
    { 
     var handler = new Mock<IAuthenticationHandler>(); 
     handler.Setup(o => o.AuthenticateAsync(It.IsAny<AuthenticateContext>())).Returns<AuthenticateContext>(c => 
     { 
      c.NotAuthenticated(); 
      return Task.FromResult(0); 
     }); 
     handler.Setup(o => o.SignInAsync(It.IsAny<SignInContext>())).Returns<SignInContext>(c => 
     { 
      c.Accept(); 
      return Task.FromResult(0); 
     }); 

     return handler; 
    } 
    public void Dispose(){} 
} 

i tak:

public class AccountControllerTests : IClassFixture<AccountControllerTestsFixture> 
{ 
    private AccountControllerTestsFixture _fixture; 

    public AccountControllerTests(AccountControllerTestsFixture fixture) 
    { 
     _fixture = fixture; 
    } 

    [Fact] 
    public async Task Login_When_Present_Provider_Version() 
    { 
     // Arrange 
     var mockedHandler = _fixture.MockSignInHandler(); 
     IServiceProvider serviceProvider = _fixture.BuildServiceProvider(mockedHandler.Object); 

     var userName = "Flattershy"; 
     var userPassword = "Angel"; 
     var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, userName) }; 

     var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>(); 
     var userManagerResult = await userManager.CreateAsync(new ApplicationUser() { Id = userName, UserName = userName, TwoFactorEnabled = false }, userPassword); 

     Assert.True(userManagerResult.Succeeded); 

     var signInManager = serviceProvider.GetRequiredService<SignInManager<ApplicationUser>>(); 

     AccountController controller = new AccountController(userManager, signInManager); 

     // Act 
     var model = new LoginArgumentsModel { UserName = userName, Password = userPassword }; 
     var result = await controller.Login(model) as Microsoft.AspNetCore.Mvc.StatusCodeResult; 

     // Assert 
     Assert.Equal((int)System.Net.HttpStatusCode.OK, result.StatusCode); 
    } 

} 

Zarówno stwardnienie szyderczy IAuthenticationHandler i tworzenia wielu klas wykonawczych IAuthenticationHandler dla każdego testu w inny sposób wygląda trochę zbyt daleko dla mnie, ale chcę również użyć serviceProvider i nie chcę kpić z userManager i signInManager. Chociaż testy napisane w ten sposób wydają się działać, chcę wiedzieć, czy istnieje jakikolwiek nieskomplikowany sposób korzystania z CookieAuthenticationHandler lub cokolwiek innego, co zachowuje się tak, jak ma to miejsce w przypadku aplikacji z app.UseIdentity().

Odpowiedz

0

Czy możesz po prostu kpić z SignInManager, trzymać go w zbiorze usług i ustawić jedno połączenie na _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: false), aby zwrócić wyniki, które chcesz przetestować dla kontrolera?

+0

Mogę i zrobiłem to kilka razy, ale nie wydaje mi się to właściwe i myślę, że takie połączenie nie wpłynie na wyśmiewanie 'HttpContext', więc bardziej skomplikowany kontroler może nie zachowywać się we właściwy sposób. Chciałbym też, aby było tak blisko oryginalnego zachowania, jak to możliwe i nie jestem zbyt dobry w kpieniu z przedmiotów. – FluffyOwl

Powiązane problemy