Signing in Users for Integration Testing with the Asp.Net Core TestHost

Georg Dangl by Georg Dangl in Web Development Monday, December 12, 2016

Monday, December 12, 2016

Posted in DotNet

When developing Asp.Net Core web apps, there's a really simple way to create integration tests for your project with the Microsoft.AspNetCore.TestHost package. In any web project, there's likely some form of authentication and authorization for specific users. Luckily, there's a really simple way that you can use to sign in users in an integration test scenario by means of evaluating a custom header without having to pass Asp.Net Core Identity cookies back and forth.

Place the following request handler method in the Startup class you're using for integration tests:

public async Task SignInIntegrationTestUser(HttpContext context)
{
    var integrationTestsUserHeader = context.Request.Headers["IntegrationTestLogin"];
    if (integrationTestsUserHeader.Count > 0)
    {
        var userName = integrationTestsUserHeader[0];
        var userManager = context.RequestServices.GetRequiredService<UserManager<ApplicationUser>>();
        var user = await userManager.FindByEmailAsync(userName);
        if (user == null)
        {
            return;
        }
        var signInManager = context.RequestServices.GetRequiredService<SignInManager<ApplicationUser>>();
        var userIdentity = await signInManager.CreateUserPrincipalAsync(user);
        context.User = userIdentity;
    }
}

Configure it in the request pipeline after app.UseIdentity() but before app.UseMvc() in your Startup.Configure() method.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
    {
        // Seed with integration tests specific data
        ServerInitialization.InitializeIntegrationTestsDatabase(serviceScope.ServiceProvider).Wait();
    }
    app.UseStaticFiles();
    app.UseIdentity();
    // To log in a user for integration tests
    // DO NOT USE IN PRODUCTION
    app.Use(next => async context =>
    {
        await SignInIntegrationTestUser(context);
        await next.Invoke(context);
    });
    app.UseMvc();
}

Generating authenticated clients is now as simple as attaching a custom header:

public static HttpClient AdminClient
{
    get
    {
        var client = _testServer.CreateClient();
        client.DefaultRequestHeaders.Add("IntegrationTestLogin", "[email protected]");
        return client;
    }
}

You can use the client to perform web requests to the TestHost, all your controllers will be aware of the UserPrincipal.

[Fact]
public async Task StatusOkForAdminUser()
{
    var client = ServerInitialization.AdminClient;
    var response = await client.GetAsync(ACTION_ROUTE);
    Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
}

Just be careful not to ever let this come near Production code!

Happy testing!


Share this post


comments powered by Disqus

About me

Hi, my name's George! I love coding and blogging about it. I focus on all things around .Net, Web Development and DevOps.

DanglIT

Need a partner for DevOps, Web Services or Software Development?

Contact me at [email protected], +49 (173) 56 45 689 or visit my professional page!

Dangl.Blog();
// Just 💗 Coding

Social Links