dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.58k stars 10.05k forks source link

WebApplicationFactory Client returns NotFound for all requests with Overriding Configure method #45372

Open mehdihadeli opened 1 year ago

mehdihadeli commented 1 year ago

Is there an existing issue for this?

Describe the bug

Hi, I create bellow custom factory for E2E test:

public class CustomWebApplicationFactory : WebApplicationFactory<Program>
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {
            // extend service collection
        });

        builder.ConfigureTestServices(services =>
        {
            // extend service collection
        });

         builder.Configure(app =>
         {
             // extend application builder
         });
    }
}

Also, this is my Program file:

using System.Reflection;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers() .AddApplicationPart(Assembly.GetExecutingAssembly());;
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.MapGet("WeatherForecast", _ =>
{
    var summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };
    return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
        TemperatureC = Random.Shared.Next(-20, 55),
        Summary = summaries[Random.Shared.Next(summaries.Length)]
    }));
});

app.Run();

public partial class Program{}

When I want to call WeatherForecast GET endpoint, with WebApplicationFactory Client I get NotFound response from client in my test instead of OK

public class UnitTest1: CustomWebApplicationFactory
{
    [Fact]
    public async Task Test1()
    {
        var response = await CreateClient().GetAsync("/WeatherForecast");
        response.Should().Be200Ok();
    }
}

If I remove below section from My CustomFactory my http client returns OK status code

  builder.Configure(app =>
 {
     // extend application builder
 });

Expected Behavior

I Expect to get a 200 ok status code for this http call on http client

Steps To Reproduce

Run this test

Exceptions (if any)

Xunit.Sdk.XunitException
Expected response to be HttpStatusCode.OK {value: 200}, but found HttpStatusCode.NotFound {value: 404}.

The HTTP response was:

HTTP/1.1 404 NotFound
Content-Length: 0

The originated HTTP request was:

GET http://localhost/WeatherForecast HTTP 1.1
Content-Length: 0

   at FluentAssertions.Execution.XUnit2TestFramework.Throw(String message)
   at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message)
   at FluentAssertions.Execution.DefaultAssertionStrategy.HandleFailure(String message)
   at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
   at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
   at FluentAssertions.Execution.AssertionScope.FailWith(String message, Object[] args)
   at FluentAssertions.Web.HttpResponseMessageAssertions.Be200Ok(String because, Object[] becauseArgs)
   at FluentAssertions.HttpStatusCodeAssertionsExtensions.Be200Ok(HttpResponseMessageAssertions`1 parent, String because, Object[] becauseArgs)
   at E2E.UnitTest1.Test1() in C:\Users\MehdiHadeli\Desktop\E2E\Test\UnitTest1.cs:line 11
   at Xunit.Sdk.TestInvoker`1.<>c__DisplayClass48_0.<<InvokeTestMethodAsync>b__1>d.MoveNext() in /_/src/xunit.execution/Sdk/Frameworks/Runners/TestInvoker.cs:line 264
--- End of stack trace from previous location ---
   at Xunit.Sdk.ExecutionTimer.AggregateAsync(Func`1 asyncAction) in /_/src/xunit.execution/Sdk/Frameworks/ExecutionTimer.cs:line 48
   at Xunit.Sdk.ExceptionAggregator.RunAsync(Func`1 code) in /_/src/xunit.core/Sdk/ExceptionAggregator.cs:line 90

.NET Version

7.0.0

Anything else?

No response

davidfowl commented 1 year ago

You can't extend the application when you override configure. We should probably throw here.

mehdihadeli commented 1 year ago

@davidfowl Why do we have this method on WebHostBuilder? Because on internal hosting process of aspnetcore? What is the usage of this Configure method?

davidfowl commented 1 year ago

It's been around since ASP.NET Core 1.0 and it's the way the application was configured we built the new hosting API.

mehdihadeli commented 1 year ago

Ok thanks :)

mehdihadeli commented 1 year ago

I think if override Program Configure functionality is not allowed, framework should throw an exception here, but both Program Configure and my override Configure in WebAppFactory run without any error. I just can catch the exception when I call my app endpoint with WebAppFactory httpclient and I get NotFound error.

davidfowl commented 1 year ago

This is a breaking change. Not saying we can't do it, but it requires doing research to understand if this will break any mainline scenarios.

captainsafia commented 1 year ago

Triage: We can consider logging an error here as an alternative to throwing an exception but that might have poor visibility to users.

As mentioned, need to do more research into impact of exception.

It might help to clarify this in the docs as well as part of https://github.com/dotnet/AspNetCore.Docs/issues/27844.

ghost commented 1 year ago

Thanks for contacting us.

We're moving this issue to the .NET 8 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

adityamandaleeka commented 1 year ago

@captainsafia Is the docs part of this done with https://github.com/dotnet/AspNetCore.Docs/issues/27844 or is there more docs work here?

captainsafia commented 1 year ago

Nope, this particular note wasn't addressed in the linked issue. We'll need to add a new note about this behavior. Likely on this page.

M-L-Ml commented 4 months ago

bellow custom factory for E2E test:

The repo of the link is absent - 404 . Sad. I need details.

HEBOS commented 6 days ago

Why would you use "UseHttpsRedirection"? WebApplicationFactory client doesn't use SSL.