Search code examples
c#asp.net-coreconsole-application.net-6.0

Is there an equivalent for WebApplicationFactory for a .NET Core console app?


I am creating integration tests for a .NET 6.0 C# console application. Is there a way to test it in the same way ASP.NET Core uses WebApplicationFactory to host and test the app? I would like to be able to change some of the dependency injection services when running my tests in the same way that you can with WebApplicationFactory, so simply running the console application or calling the Program.Main method isn't what I'm looking for.

I understand you couldn't use CreateClient and communicate with the console app using an HttpClient, but maybe keyboard inputs could be piped to it.

Currently I am using Process to manually launch it and capture the output, which works to an extent but does not provide a straightforward way to customize dependency injection, different configurations, mocking, stubbing, fakes etc. as WebApplicationFactory provides for web applications.


Solution

  • Consider using the Worker Service template instead of a plain console app and you will get dependency injection and configuration for free. Here's how you can extend WebApplicationFactory for end-to-end testing your host application.

    public class HostApplicationFactory<TEntryPoint> : WebApplicationFactory<TEntryPoint> 
        where TEntryPoint : class
    {
        private readonly Action<IWebHostBuilder> _configuration;
    
        public HostApplicationFactory(Action<IWebHostBuilder> configuration)
        {
            _configuration = configuration;
        }
    
        protected override void ConfigureWebHost(IWebHostBuilder builder) =>
            _configuration(builder.Configure(_ => { }));
    
        public Task RunHostAsync()
        {
            var host = Services.GetRequiredService<IHost>();
            return host.WaitForShutdownAsync();
        }
    }
    

    And how to use it...

    await using HostApplicationFactory<Program> hostApplicationFactory =
        new(configuration: builder =>
        {
            // Replace any appsettings like dynamic ports from test containers
            builder.UseSetting("SomeAppSetting:Key", "replacement value");
    
            builder.ConfigureTestServices(services =>
            {
                // Override any services here
            });
        });
    
    await hostApplicationFactory.RunHostAsync();
    

    This is assuming your host runs to completion and shuts down. You could also get IHostApplicationLifetime from your container to stop your application from your test.

    The biggest gotcha to note here is in the override of ConfigureWebHost. The builder.Configure(_ => { }) is needed to create an empty web application for WebApplicationFactory. Without it, you will get an error. Here's a link to the SO answer that helped me figure it out: https://stackoverflow.com/a/69974323/4465532

    Hopefully this gets you started!