FastEndpoints / FastEndpoints

A light-weight REST API development framework for ASP.NET 6 and newer.
https://fast-endpoints.com
MIT License
4.74k stars 282 forks source link

How to do Integration Testing with FastEndpoints and .Net 8 WebApplicationBuilder? #666

Closed ReneKochITTitans closed 7 months ago

ReneKochITTitans commented 7 months ago

I have a .net 8 minimal API setup:

var builder = WebApplication.CreateBuilder(args);
var app = builder.ConfigureApp();
app.Run();

// Reference for Testing Purposes of FastEndpoints
namespace BeeHive.Api
{
    public abstract class Program;
}

public static WebApplication ConfigureApp(this WebApplicationBuilder builder)
{
    builder = builder
        .ConfigureConfiguration()
        .ConfigureLogging()
        .ConfigureSwagger()
        .ConfigureDatabase()
        .ConfigureApi();

    var app = builder.Build();

    app.UseSwaggerConfig()
        .UseApi()
        .UseDatabase();

    return app;
}

Now I use the FastEnpoinds:

https://fast-endpoints.com/docs/integration-unit-testing#service-registration

With that I have a simple setup of my integration test:

public class PingPongEndpointTest(BeeHiveApiFixture app) : TestBase<BeeHiveApiFixture>
{
    [Fact]
    public async Task PingPongEndpoint_ExpectedBehaviour()
    {
        var (httpResponse, dataResponse) = await app.Client.POSTAsync<PingPongEndpoint, PingPongEndpointRequest, PingPongEndpointResponse>(
            new()
            {
                Text = "Test"
            });

        httpResponse.StatusCode.Should().Be(HttpStatusCode.OK);
        dataResponse.ReversedText.Should().Be("tseT");
    }
}

public class BeeHiveApiFixture : AppFixture<Program>
{
    protected override void ConfigureApp(IWebHostBuilder a)
    {
        // Doesnt overwrite the WebApplicationBuilder
    }
}

Now my goal is to now use the AddDbContext from my ConfigureDatabase, because this shows to a real database instead I want to overwrite this with a InMemory Database.

Normaly in the AppFixture I would like to overwrite this behauviour. But with being and IWebHostBuilder in the override from FastEndpoints and a WebApplicationBuilder in my setup this isnt overrideable (both get's called).

How to do this?

dj-nitehawk commented 7 months ago

this is how you'd typically replace the db context for tests:

public class BeeHiveApiFixture : AppFixture<Program>
{
    protected override void ConfigureServices(IServiceCollection services)
    {
        // remove the real db context configuration
        var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<MyDbContext>));
        if (descriptor != null)
            services.Remove(descriptor);

        //add a test db context
        services.AddDbContext<MyDbContext>(o => o.UseInMemoryDatabase("TestDB"));
    }
}

if that doesn't work, can you attach a standalone/debuggable repro project which i can try to fix up for you?

thanks!

dj-nitehawk commented 7 months ago

ill consider this issue sorted since you accepted the answer on stackoverflow. feel free to reopen in case you need further help. thanks!

MarkTallentire commented 2 months ago

If anyone arrives here like I did struggling to get an InMemoryDB to work I had to remove a few different services on top of the ones described in the solution above. I'm not 100% sure why but here is the code I used

Maybe @dj-nitehawk can shed some light on why we need to remove all 3?


protected override void ConfigureServices(IServiceCollection services)
    {
        var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));
        if (descriptor != null)
            services.Remove(descriptor);

        var descriptor2 = services.SingleOrDefault(d => d.ServiceType == typeof(AppDbContext));
        if (descriptor2 != null)
            services.Remove(descriptor2);

        var descriptor3 = services.SingleOrDefault(d => d.ServiceType == typeof( IDbContextOptionsConfiguration<AppDbContext>));
        if (descriptor3 != null)
            services.Remove(descriptor3);

        services.AddDbContext<AppDbContext>(x => x.UseInMemoryDatabase("TestDb"));
    }
dj-nitehawk commented 2 months ago

@MarkTallentire last i checked, just removing DbContextOptions worked fine. i don't use entity framework regularly, so i'm not sure what's going on there.

ps: this way of removing services is how it's typically done in asp.net and not anything specific to FE.