0

Description: I'm setting up integration tests for an ASP.NET Core application using the minimal hosting model in .NET 6. I am trying to mock the authentication process using a custom authentication handler. Despite my setup, the requests are returning a 401 Unauthorized status. Here are the relevant parts of my code:

TestWebApplicationFactory

namespace TX.BehaviorSpecificTests
{
    public class TestWebApplicationFactory<TProgram> : WebApplicationFactory<TProgram> where TProgram : class
    {
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            builder.ConfigureServices(services =>
            {
                // Remove the existing DbContext registration.
                var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));
                if (descriptor != null)
                {
                    services.Remove(descriptor);
                }

            // Add in-memory DbContext for testing.
            services.AddDbContext<AppDbContext>(options =>
            {
                options.UseInMemoryDatabase("InMemoryDbForTesting");
            });

            // Add mock authentication.
            services.AddAuthentication("Test")
                .AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", options => { });

            // Add controllers from the main application.
            services.AddControllers()
                .AddApplicationPart(typeof(Program).Assembly);
        });

        builder.UseEnvironment("Development");

        builder.Configure(app =>
        {
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        });
    }
}

And here is my TestAuthHandler used to Mock Authentication

   public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
   {
          public TestAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
              ILoggerFactory logger, UrlEncoder encoder)
              : base(options, logger, encoder)
          {
              HandleAuthenticateAsync();
          }
    
          protected override Task<AuthenticateResult> HandleAuthenticateAsync()
          {
              var claims = new[] { new Claim(ClaimTypes.Name, "Test user") };
              var identity = new ClaimsIdentity(claims, "Test");
              var principal = new ClaimsPrincipal(identity);
              var ticket = new AuthenticationTicket(principal, "TestScheme");
    
              var result = AuthenticateResult.Success(ticket);
    
              return Task.FromResult(result);
          }
    }
    

And this is the test code:

[Binding]
public sealed class CalculatorStepDefinitions : IClassFixture<TestWebApplicationFactory<Program>>
{
    private readonly TestWebApplicationFactory<Program> _factory;
    private HttpClient _client;
    private HttpResponseMessage _response;

    public CalculatorStepDefinitions(TestWebApplicationFactory<Program> factory)
    {
        _factory = factory;

        _client = _factory
        .CreateClient(new WebApplicationFactoryClientOptions
        {
            AllowAutoRedirect = false,
        });

    _client.DefaultRequestHeaders.Authorization =
             new AuthenticationHeaderValue(scheme: "TestScheme");
}

[Given("the second number is (.*)")]
public async Task GivenTheSecondNumberIs(int number)
{
    try
    {
        _response = await _client.GetAsync("/api/WeatherForecast/GetToday");
        _response.EnsureSuccessStatusCode();
        var content = await _response.Content.ReadAsStringAsync();
        Assert.True(_response.IsSuccessStatusCode);
    }
    catch (Exception ex)
    {
        throw;
    }
}

This is the controller I am trying to call

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

[AllowAnonymous]
[ApiController]
[Route("api/WeatherForecast")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet("GetToday")]
    public IActionResult Get()
    {
        return Ok(new { Weather = "Sunny" });
    }
}

0