XUnit.Hosting 3.0.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package XUnit.Hosting --version 3.0.1
                    
NuGet\Install-Package XUnit.Hosting -Version 3.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="XUnit.Hosting" Version="3.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="XUnit.Hosting" Version="3.0.1" />
                    
Directory.Packages.props
<PackageReference Include="XUnit.Hosting" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add XUnit.Hosting --version 3.0.1
                    
#r "nuget: XUnit.Hosting, 3.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package XUnit.Hosting@3.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=XUnit.Hosting&version=3.0.1
                    
Install as a Cake Addin
#tool nuget:?package=XUnit.Hosting&version=3.0.1
                    
Install as a Cake Tool

XUnit.Hosting

License: MIT Build Project Coverage Status XUnit.Hosting

A testing library that integrates Microsoft.Extensions.Hosting with xUnit v3, enabling dependency injection, configuration management, and hosted services in your unit tests.

Features

  • Host Builder Integration - Leverage HostApplicationBuilder in your xUnit tests
  • Dependency Injection - Full support for Microsoft.Extensions.DependencyInjection
  • Configuration Management - Use appsettings.json, user secrets, and other configuration providers
  • Memory Logger - Built-in in-memory logging provider for test verification
  • Collection Fixtures - Share application host across multiple tests

Installation

dotnet add package XUnit.Hosting

Quick Start

1. Create a Test Fixture

Create a fixture that inherits from TestApplicationFixture and configure your application services:

public class MyTestFixture : TestApplicationFixture
{
    protected override void ConfigureApplication(HostApplicationBuilder builder)
    {
        base.ConfigureApplication(builder);

        // Add configuration
        builder.Configuration.AddUserSecrets<MyTestFixture>();

        // Register services
        builder.Services.AddSingleton<IMyService, MyService>();
        
        // Add hosted services
        builder.Services.AddHostedService<MyBackgroundService>();
    }
}

2. Define a Collection

Create a collection definition to share the fixture across tests:

// support capturing console and trace output in xunit v3
[assembly: CaptureConsole]
[assembly: CaptureTrace]

[CollectionDefinition(CollectionName)]
public class MyTestCollection : ICollectionFixture<MyTestFixture>
{
    public const string CollectionName = nameof(MyTestCollection);
}

3. Write Your Tests

[Collection(MyTestCollection.CollectionName)]
public class ServiceTests : TestHostBase<MyTestFixture>
{
    public ServiceTests(MyTestFixture fixture) : base(fixture)
    {
    }

    [Fact]
    public void TestMyService()
    {
        // Arrange - Get service from DI container
        var service = Services.GetRequiredService<IMyService>();

        // Act
        var result = service.DoSomething();

        // Assert
        Assert.NotNull(result);
    }

    [Fact]
    public void TestConfiguration()
    {
        // Access configuration
        var config = Services.GetRequiredService<IConfiguration>();
        var value = config["MyKey"];
        
        Assert.NotNull(value);
    }
}

Core Components

TestApplicationFixture

Abstract base class for creating test fixtures with host support. This class implements ITestHostFixture and IDisposable, providing lazy initialization of the host to ensure it's only created when first accessed.

Key Properties:

  • Host - The IHost instance (lazily initialized and automatically started)
  • Services - IServiceProvider for dependency resolution

Methods to Override:

  • ConfigureApplication(HostApplicationBuilder builder) - Configure services, logging, and configuration. The default implementation sets the minimum log level to LogLevel.Debug and configures console logging with scopes for detailed test diagnostics.
  • CreateBuilderSettings() - Customize host builder settings such as environment name, application name, or content root path. Returns null by default to use default settings.
  • CreateHost() - Override host creation logic for advanced scenarios. The default implementation creates settings, builds the host, and starts it automatically.

TestHostBase<TFixture>

Base class for test classes that provides convenient access to the hosted test environment. This class implements IDisposable for proper cleanup of test resources.

Properties:

  • OutputHelper - ITestOutputHelper? for writing diagnostic output to the current test
  • TestContext - ITestContext providing access to test metadata and state
  • Fixture - Access to the shared test fixture (TFixture instance)
  • Services - IServiceProvider for resolving services (convenience property for Fixture.Services)

ITestHostFixture

Interface that defines the contract for XUnit collection fixtures providing access to a configured host and dependency injection container.

Properties:

  • Host - The IHost instance configured and started for the test collection
  • Services - IServiceProvider for dependency resolution (typically equivalent to Host.Services)

Memory Logger

XUnit.Hosting includes a built-in in-memory logger for capturing and asserting log output in tests.

Setup

public class MyTestFixture : TestApplicationFixture
{
    protected override void ConfigureApplication(HostApplicationBuilder builder)
    {
        base.ConfigureApplication(builder);

        // Add memory logger (registered as singleton in DI)
        builder.Logging.AddMemoryLogger();
        
        // Or with settings
        builder.Logging.AddMemoryLogger(settings =>
        {
            settings.MinimumLevel = LogLevel.Information;
            settings.Capacity = 2048;
            settings.Filter = (category, level) => level >= LogLevel.Warning;
        });
    }
}

Usage in Tests

[Collection(MyTestCollection.CollectionName)]
public class LoggingTests(MyTestFixture fixture) : TestHostBase<MyTestFixture>(fixture)
{
    [Fact]
    public void MemoryLogger()
    {
        var logger = Services.GetRequiredService<ILogger<LoggingTests>>();
        Assert.NotNull(logger);

        logger.LogInformation("This is a test log message.");

        // Retrieve the MemoryLoggerProvider to access the logs
        var memoryLoggerProvider = Services.GetRequiredService<MemoryLoggerProvider>();
        Assert.NotNull(memoryLoggerProvider);

        // Verify that the log message was captured
        var logs = memoryLoggerProvider.Logs();
        Assert.Contains(logs, log => log.Message.Contains("This is a test log message."));

        // Filter by category
        var categoryLogs = memoryLoggerProvider.Logs("XUnit.Hosting.Tests.LoggingTests");
        Assert.NotEmpty(categoryLogs);

        // Filter by log level
        var infoLogs = memoryLoggerProvider.Logs(LogLevel.Information);
        Assert.NotEmpty(infoLogs);
    }
}

MemoryLoggerSettings

Configure the memory logger with these options:

  • MinimumLevel - Minimum log level to capture (default: LogLevel.Debug)
  • Capacity - Maximum number of log entries to keep (default: 1024)
  • Filter - Custom filter function for fine-grained control

MemoryLogEntry

Log entries captured include:

  • Timestamp - DateTime when the log entry was created
  • LogLevel - The log level of the entry (Trace, Debug, Information, Warning, Error, Critical)
  • EventId - Event identifier associated with the log entry
  • Category - Category name of the logger that created this entry
  • Message - Formatted log message
  • Exception - Exception associated with the log entry, if any (nullable)
  • State - The state object passed to the logger (nullable)
  • Scopes - Read-only collection of scope values that were active when the log entry was created

Integration Testing with Docker Databases

XUnit.Hosting works seamlessly with Testcontainers to provide isolated database environments for integration tests. This approach uses IAsyncLifetime to manage container lifecycle and IHostedService to seed the database.

Install Testcontainers

dotnet add package Testcontainers.MsSql

Create a Database Fixture with Testcontainers

public class DatabaseFixture : TestApplicationFixture, IAsyncLifetime
{
    private readonly MsSqlContainer _msSqlContainer = new MsSqlBuilder()
        .WithImage("mcr.microsoft.com/mssql/server:2022-latest")
        .WithPassword("P@ssw0rd123!")
        .Build();

    public async ValueTask InitializeAsync()
    {
        await _msSqlContainer.StartAsync();
    }

    public async ValueTask DisposeAsync()
    {
        await _msSqlContainer.DisposeAsync();
    }

    protected override void ConfigureApplication(HostApplicationBuilder builder)
    {
        base.ConfigureApplication(builder);

        // Change database from container default
        var connectionBuilder = new SqlConnectionStringBuilder(_msSqlContainer.GetConnectionString());
        connectionBuilder.InitialCatalog = "SampleDataDocker";

        // Register DbContext with container connection string
        builder.Services.AddDbContext<SampleDataContext>(options =>
            options.UseSqlServer(connectionBuilder.ToString())
        );

        // Register database seeding hosted service
        builder.Services.AddHostedService<DatabaseInitialize>();
    }
}

Create a Database Seeder with IHostedService

public class DatabaseInitialize : IHostedService
{
    private readonly ILogger<DatabaseInitialize> _logger;
    private readonly SampleDataContext _dataContext;

    public DatabaseInitialize(ILogger<DatabaseInitialize> logger, SampleDataContext dataContext)
    {
        _logger = logger;
        _dataContext = dataContext;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Initialize Database StartAsync()");

        // Ensure database is created and apply migrations
        await _dataContext.Database.EnsureCreatedAsync(cancellationToken);
        // Or use migrations: await _dataContext.Database.MigrateAsync(cancellationToken);

        // Seed test data
        _dataContext.Users.AddRange(
            new User { Name = "Test User 1", Email = "user1@test.com" },
            new User { Name = "Test User 2", Email = "user2@test.com" }
        );

        await _dataContext.SaveChangesAsync(cancellationToken);
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Initialize Database StopAsync()");
        return Task.CompletedTask;
    }
}

Define the Collection

// Support capturing console and trace output
[assembly: CaptureConsole]
[assembly: CaptureTrace]

[CollectionDefinition(CollectionName)]
public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
{
    public const string CollectionName = nameof(DatabaseCollection);
}

Write Database Tests

[Collection(DatabaseCollection.CollectionName)]
public class DatabaseTests : TestHostBase<DatabaseFixture>
{
    public DatabaseTests(DatabaseFixture fixture) : base(fixture)
    {
    }

    [Fact]
    public async Task GetUser_WithValidId_ReturnsUser()
    {
        // Arrange
        var dbContext = Services.GetRequiredService<SampleDataContext>();

        // Act
        var user = await dbContext.Users.FindAsync([1], TestContext.CancellationToken);

        // Assert
        Assert.NotNull(user);
        Assert.Equal("Test User 1", user.Name);
        Assert.Equal("user1@test.com", user.Email);
    }

    [Fact]
    public async Task GetAllUsers_ReturnsSeededUsers()
    {
        // Arrange
        var dbContext = Services.GetRequiredService<SampleDataContext>();

        // Act
        var users = await dbContext.Users.ToListAsync(TestContext.CancellationToken);

        // Assert
        Assert.True(users.Count >= 2);
    }
}

Best Practices

  1. Share Expensive Resources - Use collection fixtures to share database connections, HTTP clients, etc.
  2. Clear State Between Tests - Reset or clear shared resources in test constructors if needed
  3. Use Memory Logger - Verify logging behavior in your tests
  4. Keep Fixtures Focused - Create separate fixtures for different test scenarios
  5. Leverage Configuration - Use user secrets and environment variables for test configuration

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories (1)

Showing the top 1 popular GitHub repositories that depend on XUnit.Hosting:

Repository Stars
loresoft/Injectio
Source generator that helps register attribute marked services in the dependency injection ServiceCollection
Version Downloads Last Updated
4.0.0 6,757 11/12/2025
3.1.0 524 11/7/2025
3.0.2 808 10/15/2025
3.0.1 446 10/15/2025
3.0.0 456 10/15/2025
2.0.1 1,978 6/3/2025
2.0.0 3,221 11/13/2024
1.7.2 614 10/27/2024
1.7.1 1,391 7/26/2024
1.7.0 1,642 5/10/2024
1.6.0 689 5/4/2024
1.5.0 1,143 3/20/2024
1.2.0 744 12/21/2023
1.1.0 534 11/21/2023
1.0.0 700 9/7/2023
1.0.0-beta.2 189 9/7/2023
1.0.0-beta.1 161 9/7/2023