Codebelt
v11.1.2

Codebelt.Extensions.Xunit.Hosting

Host-aware xUnit testing with Microsoft DI: configure services, resolve dependencies, and assert against a running IHost inside your test methods.

.NET 10.0 / .NET 9.0 / .NET Standard 2.0 MIT 56,793 downloads

Overview

Codebelt.Extensions.Xunit.Hosting extends Codebelt.Extensions.Xunit to bring Microsoft.Extensions.Hosting and Microsoft.Extensions.DependencyInjection into xUnit tests. It provides base classes, fixtures, and factories that let you configure services, build an IHost, and resolve dependencies directly inside test methods.

The package supports three hosting styles: the classic IHostBuilder pattern via HostTest<T>, the modern minimal API style via MinimalHostTest<T>, and application entry-point bootstrapping via ApplicationTest<TEntryPoint, T>. Each style uses xUnit's IClassFixture<T> mechanism for shared context and scoped service support.

Key APIs

ApplicationTestFactory provides the simplest entry point for testing an existing .NET application. Its Create<TEntryPoint> method bootstraps the host from the assembly containing TEntryPoint, returns a disposable IHostTest with Host, Configuration, and Environment properties, and accepts an optional delegate to override the IHostBuilder before the host is built.

HostTestFactory creates an IHostTest for generic-host scenarios without requiring a test class. The Create method accepts Action<IServiceCollection> and Action<IHostBuilder> delegates, while CreateWithHostBuilderContext provides access to the HostBuilderContext during service configuration.

MinimalHostTestFactory mirrors HostTestFactory but uses Host.CreateApplicationBuilder internally, aligning with the modern minimal hosting model. It accepts Action<IHostApplicationBuilder> instead of Action<IHostBuilder>.

HostTest<T> is the primary base class for test classes that need a fully configured IHost. It implements IClassFixture<T> where T : class, IGenericHostFixture, and requires subclasses to implement the abstract ConfigureServices(IServiceCollection) method. The base constructor wires up the fixture, builds the host, and exposes Host, Configuration, and Environment.

MinimalHostTest<T> serves the same role for the minimal hosting model. It implements IClassFixture<T> where T : class, IMinimalHostFixture and provides a virtual ConfigureHost(IHostApplicationBuilder) method that subclasses override to register services on the builder's Services property.

ApplicationTest<TEntryPoint, T> is the base class for tests that bootstrap an existing application entry point. It implements IClassFixture<T> where T : class, IApplicationFixture<TEntryPoint>, and provides a virtual ConfigureHost(IHostBuilder) hook for overriding host configuration before the application host is built.

ManagedHostFixture and ManagedMinimalHostFixture are the default fixture implementations for IGenericHostFixture and IMinimalHostFixture respectively. They build the IHost, set the environment to Development, and start the host asynchronously. BlockingManagedApplicationFixture<TEntryPoint> is the corresponding fixture for application entry-point testing, starting the host synchronously.

ServiceCollectionExtensions adds AddXunitTestLogging overloads that register an ILoggerProvider backed by xUnit's ITestOutputHelper, making log output visible in test results. AddXunitTestLoggingOutputHelperAccessor registers an ITestOutputHelperAccessor for scenarios where the test output helper needs to be resolved from DI.

ServiceProviderExtensions provides GetRequiredScopedService<T>, which creates a scope, resolves the service, and disposes the scope in a single call.

Basic usage

using Codebelt.Extensions.Xunit;
using Codebelt.Extensions.Xunit.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Xunit;

namespace MyProject.Tests;

public class HostTestFactoryTest : Test
{
    public HostTestFactoryTest(ITestOutputHelper output) : base(output)
    {
    }

    [Fact]
    public void Create_WithServiceRegistration_ShouldResolveScopedService()
    {
        using var hostTest = HostTestFactory.Create(services =>
        {
            services.AddScoped<IMarker, Marker>();
            services.AddXunitTestLogging(TestOutput);
        });

        using var scope = hostTest.Host.Services.CreateScope();
        var marker = scope.ServiceProvider.GetRequiredService<IMarker>();

        Assert.NotNull(marker);
        Assert.Equal("Hosting", marker.Value);
        TestOutput.WriteLine($"Resolved {nameof(IMarker)}: {marker.Value}");
    }

    private interface IMarker
    {
        string Value { get; }
    }

    private class Marker : IMarker
    {
        public string Value => "Hosting";
    }
}

Use this pattern when you need to verify that services resolve correctly from a configured IHost without creating a dedicated test class and fixture pair. HostTestFactory.Create builds and starts the host inline, so the test method can immediately query the service provider.

When your tests need shared host state across multiple test methods in the same class, derive from HostTest<T> or MinimalHostTest<T> instead and let xUnit manage the fixture lifecycle through IClassFixture<T>.

Installation

dotnet add package Codebelt.Extensions.Xunit.Hosting

Usage guidance

This package is the right choice when your unit tests need to exercise code that depends on Microsoft.Extensions.DependencyInjection or Microsoft.Extensions.Hosting. The factory methods (HostTestFactory, MinimalHostTestFactory, ApplicationTestFactory) work well for one-off host assertions, while the base classes (HostTest<T>, MinimalHostTest<T>, ApplicationTest<TEntryPoint, T>) suit test classes that share a host across multiple facts. If your tests target ASP.NET Core middleware, controllers, or HTTP endpoints, the sibling package Codebelt.Extensions.Xunit.Hosting.AspNetCore provides WebHostTestFactory and WebApplicationTestFactory with TestServer integration built in.

Family packages