WebApplicationFactory always return 404 for controllers calls in .net core 6
Asked Answered
I

4

9

I followed the documentation of microsoft for Integration testing: https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0#introduction-to-integration-tests

In .net core 6, startup.cs has been removed, the integration testing I used before doesn't work anymore as is. I need to do an update.

In my API csproj, I added:

<ItemGroup>
        <InternalsVisibleTo Include="Integration.Tests" />
</ItemGroup>

and here is the Integration.Tests csproj:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <IsPackable>false</IsPackable>
        <IsTestProject>true</IsTestProject>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
        <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0" />
        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.0" />
        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
        <PackageReference Include="xunit" Version="2.4.1" />
        <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
            <PrivateAssets>all</PrivateAssets>
        </PackageReference>
        <PackageReference Include="coverlet.collector" Version="3.1.0">
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
            <PrivateAssets>all</PrivateAssets>
        </PackageReference>
    </ItemGroup>

    

</Project>

I created a TestWebAppFactory.cs like:

public class TestWebAppFactory<TEntryPoint> : WebApplicationFactory<Program> where TEntryPoint : Program
{
    public ITestOutputHelper Output { get; set; }
    public List<string> Logs { get; private set; } = new List<string>();

    public TestWebAppFactory([NotNull] ITestOutputHelper output)
    {
        Output = output;
    }

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder
            .ConfigureServices(services =>
            {
                var descriptor = services.SingleOrDefault(
                    d => d.ServiceType ==
                        typeof(DbContextOptions<MyDbContext>));

                if (descriptor != null)
                {
                    services.Remove(descriptor);
                }

                services.AddDbContext<MyDbContext>(options =>
                {
                    options.UseInMemoryDatabase("My.Sample");
                });
            })
            .Configure(app =>  {
                var serviceProvider = app.ApplicationServices;
                using var scope = serviceProvider.CreateScope();
                var itemManager = serviceProvider.GetRequiredService<IItemManager>();
                TestDbInitializer.Seed(scope.ServiceProvider, Output);
            });

    }
}

And my Item_Tests.cs:

public class Items_Tests : IClassFixture<Program>
    {
        private readonly HttpClient _client;
        private readonly TestServer _server;
        private readonly IWebHost _host;

        public Items_Tests(ITestOutputHelper output)
        {
            var factory = new TestWebAppFactory<Program>(output);
            _client = factory
                .CreateClient();
        } 

        [Fact]
        public async Task Index_WhenCalled_ReturnsApplicationForm()
        {
            var response = await _client.GetAsync(Constants.Api.V1.Items.Url);

            response.EnsureSuccessStatusCode();

            var responseString = await response.Content.ReadAsStringAsync();

            Assert.Contains("Mark", responseString);
            Assert.Contains("Evelin", responseString);
        }

    }

Note: I would like to be able to send the ITestOuputHelper to TestWebAppFactory to write few information useful in the output that I don't share here to reduce the amount of code.

Note2: When I launch the API, every thing works correctly, I'm to see my controller in Swagger and call the get with a code 200 returnsw.

So each time the test fails here:

            var response = await _client.GetAsync(Constants.Api.V1.Items.Url);

            response.EnsureSuccessStatusCode();

The response always get a 404 error.

What should I do to make it works correctly?

Thanks

Interlocutress answered 10/12, 2021 at 4:13 Comment(0)
I
6

So finally I found why I get a 404, when I delete the .Configure section in TestWebAppFactory I'm able to connect to the API.

So now I need to found how to seed data during my test :)

Interlocutress answered 15/12, 2021 at 15:0 Comment(2)
Did you find out more? I'm getting a 404 on a minimal project. Don't even ConfigureWebHost. Just a controller endpoint returning 200Cyclades
Check what I have done there: github.com/ranouf/net60withnswag/tree/main/tests/… maybe it will help you, let me knowInterlocutress
S
3

I had exacly the same problem. In my case, I didn't have any parameters in CreateBuilder() method when creating a builder. The solution for me was to add args parameter to CreateBuilder like below.

var builder = WebApplication.CreateBuilder(args);
Sternberg answered 2/11, 2022 at 20:50 Comment(0)
B
1

The reason for me was to get rid of ApplicationName from WebApplicationOptions that you can pass as parameter to one of the WebApplication.CreateBuilder overloads

Boiling answered 1/2, 2023 at 7:46 Comment(0)
S
0

Please note that the testproject needs to be a web SDK project: <Project Sdk="Microsoft.NET.Sdk.Web"> in your .csproj.

From https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0 See

With ASP.NET Core 8 (not tested 6), I get always a 404 when the integration test project is a <Project Sdk="Microsoft.NET.Sdk">

Serrano answered 30/7 at 13:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.