Integration testing with in-memory IdentityServer

前端 未结 7 1562
一生所求
一生所求 2020-12-07 17:23

I have an API that uses IdentityServer4 for token validation. I want to unit test this API with an in-memory TestServer. I\'d like to host the IdentityServer in the in-memor

7条回答
  •  抹茶落季
    2020-12-07 17:38

    We stepped away from trying to host a mock IdentityServer and used dummy/mock authorizers as suggested by others here.

    Here's how we did that in case it's useful:

    Created a function which takes a type, creates a test Authentication Middleware and adds it to the DI engine using ConfigureTestServices (so that it's called after the call to Startup.)

    internal HttpClient GetImpersonatedClient() where T : AuthenticationHandler
        {
            var _apiFactory = new WebApplicationFactory();
    
            var client = _apiFactory
                .WithWebHostBuilder(builder =>
                {
                    builder.ConfigureTestServices(services =>
                    {
                        services.AddAuthentication("Test")
                            .AddScheme("Test", options => { });
                    });
                })
                .CreateClient(new WebApplicationFactoryClientOptions
                {
                    AllowAutoRedirect = false,
                });
    
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Test");
    
            return client;
        }
    

    Then we create what we called 'Impersonators' (AuthenticationHandlers) with the desired roles to mimic users with roles (We actually used this as a base class, and create derived classes based on this to mock different users):

    public abstract class FreeUserImpersonator : AuthenticationHandler
    {
        public Impersonator(
            IOptionsMonitor options,
            ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
            : base(options, logger, encoder, clock)
        {
            base.claims.Add(new Claim(ClaimTypes.Role, "FreeUser"));
        }
    
        protected List claims = new List();
    
        protected override Task HandleAuthenticateAsync()
        {
            var identity = new ClaimsIdentity(claims, "Test");
            var principal = new ClaimsPrincipal(identity);
            var ticket = new AuthenticationTicket(principal, "Test");
    
            var result = AuthenticateResult.Success(ticket);
    
            return Task.FromResult(result);
        }
    }
    

    Finally, we can perform our integration tests as follows:

    // Arrange
    HttpClient client = GetImpersonatedClient();
    
    // Act
    var response = await client.GetAsync("api/things");
    
    // Assert
    Assert.That.IsSuccessful(response);
    

提交回复
热议问题