Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integration testing a .NET Core 3 Worker

ASP.NET Core has WebApplicationFactory<T> that can be used to start up a test host for integration test purposes.

Is there an equivalent for a non ASP.NET Core project? I'm thinking of the ".NET Core Worker Service Template" for example. It doesn't have any references to ASP.NET Core, but it uses the generic host.

For example, I have a project like this one, hosted as a windows service. I would like to create integration tests as easily for this as I do for ASP.NET Core projects (where I can reuse DI from the Startup file, so I don't need to set that up in the test.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((context, builder) =>
            {
                builder.AddAppSettings(context.HostingEnvironment.EnvironmentName);
            })
            .ConfigureServices((hostContext, services) =>
            {
                // Loads of configuration (DI, Logging, Messaging, etc) removed for brevity
                // ...
            })
            .UseWindowsService();
}

In this case the service listens for messages (using Masstransit) so there is no HostedService setup. But there might be as well in other cases.

like image 477
Joel Avatar asked May 02 '26 08:05

Joel


1 Answers

I had the similar situation, with the difference I was using Rabbit MQ queue. To create a test that extract messages using a .NET CORE windows service, I had to create separate projects, out of the main one, that is the windows service host project.

In my case, I had a class named MessageConsumer located in a separate project with namespace OrdersMessageConsumer.RabbitMQ and implementing the IMessageConsumer interface.

Then, I created a base test class (using MS Test project .NET CORE 3.1) where I set up the host used from my tests:

[TestClass]
public abstract class BaseTest
{
    protected IServiceProvider ServiceProvider { get; set; }

    [TestInitialize]
    public virtual void TestInitialize()
    {           
        var host = Host.CreateDefaultBuilder(default(string[]))
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddJsonFile("appsettings.json");
            })
            .ConfigureServices(DependencyRegistrationBuilder.SetUp)
            .Build();

        this.ServiceProvider = host.Services;
    }

Here, in order to avoid repeating dependency resolution registrations, I created a another different project where I had a static class called DependencyRegistrationBuilder with SetUp() method containing all my dependencies resolution registration:

public static class DependencyRegistrationBuilder
{
    public static void SetUp(HostBuilderContext hostContext, IServiceCollection services)
    {
        ...
        services.AddSingleton<IMessageConsumer, OrdersMessageConsumer.RabbitMQ.MessageConsumer>();

        ...
    }
}

This static class was - of course - used by my .NET CORE 3.1 Windows Service host project too, as shown below:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                var env = hostingContext.HostingEnvironment;
                config.AddJsonFile("appsettings.json");
                config.AddJsonFile($"appsettings.{env.EnvironmentName}.json");
            })
            .ConfigureServices(DependencyRegistrationBuilder.SetUp)
            .UseNLog()
            .UseWindowsService();
}

In the end, from my test I requested the messages consumer class and then I called its consume method as shown below:

[TestClass]
public class UnitTest1 : BaseTest
{
    [TestMethod]
    public void TestMethod1()
    {
        var msgConsumer = (IMessageConsumer)base.ServiceProvider.GetService(
            typeof(IMessageConsumer));

        msgConsumer.ConsumeMessage();
    }
}
like image 107
Christian Del Bianco Avatar answered May 04 '26 21:05

Christian Del Bianco



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!