2016-07-26 22 views
5

私のAccountControllerMusiStore例からのテストに基づいてこのような簡単なメソッドをテストしようとしています。そのためにどのように適切にIAuthenticationHandlerを模倣するASP.NETコアコントローラのユニットテスト中

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

私は最終的にHttpAuthenticationFeatureで使用するためのIAuthenticationHandlerの代用を書く使用するように私を強制的に両方UserManagerSignInManagerを使用する必要があります。最後に、テストは次のように判明:

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(){} 
} 

と、この:

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

} 

どちらも複数のIAuthenticationHandlerをからかっと異なる方法で各テストのIAuthenticationHandlerを実装する複数のクラスを作成するには、私にとってはあまりにも遠く少し見えます、 ServiceProviderを使用したいので、userManagersignInManagerをモックしたくありません。このように書かれたテストはうまくいくように見えますが、CookieAuthenticationHandlerなどの複雑な方法や、app.UseIdentity()を使ってアプリケーションを動作させる何かがあるかどうかを知りたいと思っています。

答えて

0

SignInManagerをモックしてサービスコレクションに貼り付け、_signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: false)の呼び出しを設定して、コントローラのテスト結果を返すことはできますか?

+0

私はこれを数回行うことができますが、それは私にはうってつけではないと思います。そのような呼び出しは模倣された 'HttpContext'には影響しないと思うので、より複雑なコントローラは適切な振る舞いをしません。また、私はそれができるだけ元の動作に近いものにしたい、私はオブジェクトを嘲笑ではあまりよくありません。 – FluffyOwl

関連する問題