From ecae0f185754fe30439960c7d4cd09265f5c3b2d Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 13:24:37 +0200 Subject: [PATCH 01/15] =?UTF-8?q?=F0=9F=93=A6=20upgrade=20xunit=20to=20v4?= =?UTF-8?q?=20and=20supporting=20dependencies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upgrade xunit framework suite from v3.2.2 to v4.0.0 with supporting package version updates: Codebelt.Bootstrapper packages to v5.2.1, Extensions.BenchmarkDotNet.Console to v1.3.3, and Microsoft.NET.Test.Sdk to v18.9.0. xunit v4 is a major version bump with breaking changes that requires code updates for full compatibility. --- Directory.Packages.props | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 58e221c..f7ca117 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,25 +6,25 @@ - - - - + + + + - + - - - - - + + + + + From cee5feaea546f553896428cb6de90912f67879b3 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 13:24:48 +0200 Subject: [PATCH 02/15] =?UTF-8?q?=F0=9F=94=A7=20update=20test=20and=20buil?= =?UTF-8?q?d=20infrastructure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate Docker test environments from separate net9 and net10 images into a unified ubuntu-testrunner:8-9-10-11 image for improved maintainability. Update DocFX base image from nginx 1.31-alpine to nginx 1.31-alpine and bump docfx from 2.78.4 to 2.78.5. --- .docfx/Dockerfile.docfx | 4 ++-- testenvironments.json | 9 ++------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/.docfx/Dockerfile.docfx b/.docfx/Dockerfile.docfx index a425700..3ebeaa3 100644 --- a/.docfx/Dockerfile.docfx +++ b/.docfx/Dockerfile.docfx @@ -1,9 +1,9 @@ -ARG NGINX_VERSION=1.31-alpine +ARG NGINX_VERSION=1.31-alpine FROM --platform=$BUILDPLATFORM nginx:${NGINX_VERSION} AS base RUN rm -rf /usr/share/nginx/html/* -FROM --platform=$BUILDPLATFORM codebeltnet/docfx:2.78.4 AS build +FROM --platform=$BUILDPLATFORM codebeltnet/docfx:2.78.5 AS build ADD [".", "docfx"] diff --git a/testenvironments.json b/testenvironments.json index e0b5a26..587b2ef 100644 --- a/testenvironments.json +++ b/testenvironments.json @@ -7,14 +7,9 @@ "wslDistribution": "Ubuntu-24.04" }, { - "name": "Docker-Ubuntu (net9)", + "name": "Docker-Ubuntu", "type": "docker", - "dockerImage": "codebeltnet/ubuntu-testrunner:9" - }, - { - "name": "Docker-Ubuntu (net10)", - "type": "docker", - "dockerImage": "codebeltnet/ubuntu-testrunner:10" + "dockerImage": "codebeltnet/ubuntu-testrunner:8-9-10-11" } ] } From 54607e862ca43e925d5f995145f5f8b9ceed0eb9 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 13:24:58 +0200 Subject: [PATCH 03/15] =?UTF-8?q?=F0=9F=8E=A8=20clean=20up=20editor=20conf?= =?UTF-8?q?iguration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove obsolete analyzer rules no longer needed for code style enforcement: CA1200 (cref tag prefix usage) and IDE0330 (System.Threading.Lock). These rules were disabled due to compatibility constraints with older target frameworks that are no longer relevant. Also fix typo in IDE0036 comment. --- .editorconfig | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/.editorconfig b/.editorconfig index 85dcc19..6d0e3c9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -82,11 +82,6 @@ dotnet_diagnostic.IDE0078.severity = none [*.{cs,vb}] dotnet_diagnostic.IDE0290.severity = none -# CA1200: Avoid using cref tags with a prefix -# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1200 -[*.{cs,vb}] -dotnet_diagnostic.CA1200.severity = none - # IDE0305: Use collection expression for fluent # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0305 [*.{cs,vb}] @@ -176,12 +171,6 @@ dotnet_diagnostic.IDE0032.severity = none # Order modifiers # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0036 -# Excluded because of inconsistency with other analyzers +# Excluded becuase of inconsistency with other analyzers [*.{cs,vb}] dotnet_diagnostic.IDE0036.severity = none - -# Use 'System.Threading.Lock' -# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0330 -# Excluded while TFMs are less than net9.0 -[*.{cs,vb}] -dotnet_diagnostic.IDE0330.severity = none From b4500ba86ee4dfdf7bc9f5eb8f35d08270a515bf Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 13:25:08 +0200 Subject: [PATCH 04/15] =?UTF-8?q?=F0=9F=99=88=20add=20git=20attributes=20c?= =?UTF-8?q?onfiguration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add .gitattributes file to ensure consistent line-ending handling across the repository. Configures text file normalization and merge strategies for version-control files to reduce merge conflicts and ensure consistency across Windows and Unix-like environments. --- .gitattributes | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain From 46ad309c12a04aac66277ad44a7f5b09a64bb5b3 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 14:38:28 +0200 Subject: [PATCH 05/15] =?UTF-8?q?=F0=9F=92=A5=20remove=20BlockingManagedAp?= =?UTF-8?q?plicationFixture=20and=20update=20defaults?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a breaking change for v12.0.0. BlockingManagedApplicationFixture and BlockingManagedWebApplicationFixture have been removed as deprecated types. Applications must migrate to ManagedApplicationFixture and ManagedWebApplicationFixture, which now serve as the default fixtures in ApplicationTestFactory and WebApplicationTestFactory respectively. This aligns the framework with entrypoint-owned deferred host startup patterns. --- ...ns.Xunit.Hosting.ApplicationTestFactory.md | 2 +- ...lockingManagedWebApplicationFixture%601.md | 52 ------------- ...ng.AspNetCore.WebApplicationTestFactory.md | 2 +- ...g.BlockingManagedApplicationFixture%601.md | 48 ------------ .../BlockingManagedWebApplicationFixture.cs | 78 ------------------- .../WebApplicationTestFactory.cs | 10 +-- .../ApplicationTestFactory.cs | 8 +- .../BlockingManagedApplicationFixture.cs | 72 ----------------- 8 files changed, 9 insertions(+), 263 deletions(-) delete mode 100644 .docfx/api/types/Codebelt.Extensions.Xunit.Hosting.AspNetCore.BlockingManagedWebApplicationFixture%601.md delete mode 100644 .docfx/api/types/Codebelt.Extensions.Xunit.Hosting.BlockingManagedApplicationFixture%601.md delete mode 100644 src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/BlockingManagedWebApplicationFixture.cs delete mode 100644 src/Codebelt.Extensions.Xunit.Hosting/BlockingManagedApplicationFixture.cs diff --git a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.ApplicationTestFactory.md b/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.ApplicationTestFactory.md index 01cf124..641c4d0 100644 --- a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.ApplicationTestFactory.md +++ b/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.ApplicationTestFactory.md @@ -4,7 +4,7 @@ example: - *content --- -The test project references a worker application whose entry point registers `WorkerIdentity`. `ApplicationTestFactory` runs that application's real host setup, then exposes its services and environment through an owned test context so the test can verify application behavior without recreating `Program` configuration. +The test project references a worker application whose entry point registers `WorkerIdentity`. `ApplicationTestFactory` uses `ManagedApplicationFixture` by default, runs that application's real host setup, and exposes its services and environment through an owned test context so the test can verify application behavior without recreating `Program` configuration. Pass an explicit `IApplicationFixture` when the test needs a different lifecycle. ```csharp using Codebelt.Extensions.Xunit.Hosting; diff --git a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.AspNetCore.BlockingManagedWebApplicationFixture%601.md b/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.AspNetCore.BlockingManagedWebApplicationFixture%601.md deleted file mode 100644 index 59c530f..0000000 --- a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.AspNetCore.BlockingManagedWebApplicationFixture%601.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -uid: Codebelt.Extensions.Xunit.Hosting.AspNetCore.BlockingManagedWebApplicationFixture`1 -example: -- *content ---- - -The test project references a minimal ASP.NET Core application and shares its in-memory server through xUnit's class-fixture lifetime. `BlockingManagedWebApplicationFixture` is an obsolete compatibility fixture that preserves the legacy blocking startup path for the current minor release; new tests should use `ManagedWebApplicationFixture` so the real application entry point owns startup. This compatibility type should be removed or changed in the next major release. - -```csharp -using System.Threading.Tasks; -using Codebelt.Extensions.Xunit.Hosting.AspNetCore; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace CatalogApi.Tests; - -public sealed class CatalogApiTest : IClassFixture> -{ - private readonly BlockingManagedWebApplicationFixture _fixture; - - public CatalogApiTest(BlockingManagedWebApplicationFixture fixture) - { - _fixture = fixture; - } - - [Fact] - public async Task HealthEndpoint_ReturnsApplicationState() - { - using var client = _fixture.Server.CreateClient(); - - var body = await client.GetStringAsync("/health").ConfigureAwait(false); - - Assert.Equal("ready", body); - } -} - -public sealed record CatalogStatus(string Value); - -public sealed class CatalogProgram -{ - public static void Main(string[] args) - { - var builder = WebApplication.CreateBuilder(args); - builder.Services.AddSingleton(new CatalogStatus("ready")); - - var app = builder.Build(); - app.MapGet("/health", (CatalogStatus status) => status.Value); - app.Run(); - } -} -``` diff --git a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.AspNetCore.WebApplicationTestFactory.md b/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.AspNetCore.WebApplicationTestFactory.md index 57bc791..0d93104 100644 --- a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.AspNetCore.WebApplicationTestFactory.md +++ b/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.AspNetCore.WebApplicationTestFactory.md @@ -4,7 +4,7 @@ example: - *content --- -The test project references a minimal ASP.NET Core application with a `/health` endpoint. `WebApplicationTestFactory` runs that real entry point on `TestServer`, applies a test-only service override through `IWebHostBuilder`, and gives the test an owned host from which it creates an HTTP client. +The test project references a minimal ASP.NET Core application with a `/health` endpoint. `WebApplicationTestFactory` uses `ManagedWebApplicationFixture` by default, runs that real entry point on `TestServer`, applies a test-only service override through `IWebHostBuilder`, and gives the test an owned host from which it creates an HTTP client. Pass an explicit `IWebApplicationFixture` when the test needs a different lifecycle. ```csharp using System.Threading.Tasks; diff --git a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.BlockingManagedApplicationFixture%601.md b/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.BlockingManagedApplicationFixture%601.md deleted file mode 100644 index 409276a..0000000 --- a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.BlockingManagedApplicationFixture%601.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -uid: Codebelt.Extensions.Xunit.Hosting.BlockingManagedApplicationFixture`1 -example: -- *content ---- - -The test project references a worker application's entry point and shares one bootstrapped host through xUnit's class-fixture lifetime. `BlockingManagedApplicationFixture` is an obsolete compatibility fixture that preserves the legacy blocking startup path for the current minor release; new tests should use `ManagedApplicationFixture` so the real application entry point owns startup. This compatibility type should be removed or changed in the next major release. - -```csharp -using Codebelt.Extensions.Xunit.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Xunit; - -namespace InventoryWorker.Tests; - -public sealed class InventoryWorkerTest : IClassFixture> -{ - private readonly BlockingManagedApplicationFixture _fixture; - - public InventoryWorkerTest(BlockingManagedApplicationFixture fixture) - { - _fixture = fixture; - } - - [Fact] - public void Host_ContainsApplicationService() - { - var identity = _fixture.Host.Services.GetRequiredService(); - - Assert.Equal("Inventory worker", identity.Name); - } -} - -public sealed record WorkerIdentity(string Name); - -public sealed class WorkerProgram -{ - public static void Main(string[] args) - { - var builder = Host.CreateApplicationBuilder(args); - builder.Services.AddSingleton(new WorkerIdentity("Inventory worker")); - - using var host = builder.Build(); - host.Run(); - } -} -``` diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/BlockingManagedWebApplicationFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/BlockingManagedWebApplicationFixture.cs deleted file mode 100644 index cc425af..0000000 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/BlockingManagedWebApplicationFixture.cs +++ /dev/null @@ -1,78 +0,0 @@ -using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Internal; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; - -/// -/// Provides a blocking managed implementation of the interface. -/// -/// A type in the entry point assembly of the application. -/// -/// -/// -/// Unlike the base managed web host fixtures, this fixture starts the resolved application host synchronously. -/// ASP.NET Core application entry point testing must expose a started after fixture initialization. -/// Use for entrypoint-owned startup in new tests. -/// This compatibility fixture is retained for the current minor release and should be removed or changed in the next major release. -/// -[Obsolete("Use ManagedWebApplicationFixture so the application entry point owns host startup. This compatibility fixture will be removed or changed in the next major release.")] -public class BlockingManagedWebApplicationFixture : HostFixture, IWebApplicationFixture where TEntryPoint : class -{ - /// - /// Initializes a new instance of the class. - /// - public BlockingManagedWebApplicationFixture() - { - AsyncHostRunnerCallback = (host, _) => - { - host.Start(); - return Task.CompletedTask; - }; - } - - /// - /// Creates and configures the of this instance. - /// - /// The object that inherits from . - /// was added to support those cases where the caller is required in the host configuration. - /// - /// is null. - /// - /// - /// is not assignable from . - /// - public virtual void ConfigureHost(Test hostTest) - { - ArgumentNullException.ThrowIfNull(hostTest); - if (!HasTypes(hostTest.GetType(), typeof(WebApplicationTest<,>))) { throw new ArgumentOutOfRangeException(nameof(hostTest), typeof(WebApplicationTest<,>), $"{nameof(hostTest)} is not assignable from WebApplicationTest."); } - if (this.HasValidState()) { return; } - - Host = WebApplicationHostFactory.Create(ConfigureWebHostCallback); - Server = Host.GetTestServer(); - Configuration = Host.Services.GetRequiredService(); - Environment = Host.Services.GetRequiredService(); - - ConfigureCallback(Configuration, Environment); - - AsyncHostRunnerCallback(Host, CancellationToken.None); - } - - /// - /// Gets or sets the delegate that provides a way to override the before the application is built. - /// - /// The delegate that provides a way to override the . - public Action ConfigureWebHostCallback { get; set; } - - /// - /// Gets the initialized by this instance. - /// - /// The initialized by this instance. - public TestServer Server { get; protected set; } -} diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebApplicationTestFactory.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebApplicationTestFactory.cs index 1dbe47c..4ef00f0 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebApplicationTestFactory.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebApplicationTestFactory.cs @@ -17,16 +17,14 @@ public static class WebApplicationTestFactory /// /// A type in the entry point assembly of the application. /// The which may be configured. - /// An optional implementation to use instead of the default instance. + /// An optional implementation to use instead of the default instance. /// An instance of an implementation. /// - /// Passing a opts this call into entrypoint-owned deferred startup. Omitting preserves the blocking compatibility path for the current minor release; that default should be removed or changed in the next major release. + /// When is omitted, the factory uses so the application entry point owns deferred host startup. Pass another implementation when the test requires a different lifecycle. /// public static IHostTest Create(Action webHostSetup = null, IWebApplicationFixture hostFixture = null) where TEntryPoint : class { - // Minor-release compatibility: keep the historical blocking default while allowing callers to opt in by passing ManagedWebApplicationFixture. - // Major release: remove or change this default when the compatibility fixture is retired. Hint: ManagedWebApplicationFixture - return new Internal.WebApplicationTest(webHostSetup, hostFixture ?? new BlockingManagedWebApplicationFixture()); + return new Internal.WebApplicationTest(webHostSetup, hostFixture ?? new ManagedWebApplicationFixture()); } /// @@ -35,7 +33,7 @@ public static IHostTest Create(Action webHostSetup /// A type in the entry point assembly of the application. /// The which may be configured. /// The function delegate that creates a from the . Default is a GET request to the root URL ("/"). - /// An optional implementation to use instead of the default instance. + /// An optional implementation to use instead of the default instance. /// A that represents the asynchronous operation. The task result contains the for the test server. public static async Task RunAsync(Action webHostSetup = null, Func> responseFactory = null, IWebApplicationFixture hostFixture = null) where TEntryPoint : class { diff --git a/src/Codebelt.Extensions.Xunit.Hosting/ApplicationTestFactory.cs b/src/Codebelt.Extensions.Xunit.Hosting/ApplicationTestFactory.cs index 31894f5..59ba412 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/ApplicationTestFactory.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/ApplicationTestFactory.cs @@ -13,15 +13,13 @@ public static class ApplicationTestFactory /// /// A type in the entry point assembly of the application. /// The which may be configured. - /// An optional implementation to use instead of the default instance. + /// An optional implementation to use instead of the default instance. /// An instance of an implementation. /// - /// Passing a opts this call into entrypoint-owned deferred startup. Omitting preserves the blocking compatibility path for the current minor release; that default should be removed or changed in the next major release. + /// When is omitted, the factory uses so the application entry point owns deferred host startup. Pass another implementation when the test requires a different lifecycle. /// public static IHostTest Create(Action hostSetup = null, IApplicationFixture hostFixture = null) where TEntryPoint : class { - // Minor-release compatibility: keep the historical blocking default while allowing callers to opt in by passing ManagedApplicationFixture. - // Major release: remove or change this default when the compatibility fixture is retired. Hint: ManagedApplicationFixture - return new Internal.ApplicationTest(hostSetup, hostFixture ?? new BlockingManagedApplicationFixture()); + return new Internal.ApplicationTest(hostSetup, hostFixture ?? new ManagedApplicationFixture()); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/BlockingManagedApplicationFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting/BlockingManagedApplicationFixture.cs deleted file mode 100644 index df6124b..0000000 --- a/src/Codebelt.Extensions.Xunit.Hosting/BlockingManagedApplicationFixture.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Codebelt.Extensions.Xunit.Hosting; - -/// -/// Provides a blocking managed implementation of the interface. -/// -/// A type in the entry point assembly of the application. -/// -/// -/// -/// Unlike the base managed host fixtures, this fixture starts the resolved application host synchronously. -/// Application entry point testing must expose a fully started host after fixture initialization. -/// Use for entrypoint-owned startup in new tests. -/// This compatibility fixture is retained for the current minor release and should be removed or changed in the next major release. -/// -[Obsolete("Use ManagedApplicationFixture so the application entry point owns host startup. This compatibility fixture will be removed or changed in the next major release.")] -public class BlockingManagedApplicationFixture : HostFixture, IApplicationFixture where TEntryPoint : class -{ - /// - /// Initializes a new instance of the class. - /// - public BlockingManagedApplicationFixture() - { - AsyncHostRunnerCallback = (host, _) => - { - host.Start(); - return Task.CompletedTask; - }; - } - - /// - /// Creates and configures the of this instance. - /// - /// The object that inherits from . - /// was added to support those cases where the caller is required in the host configuration. - /// - /// is null. - /// - /// - /// is not assignable from . - /// - public virtual void ConfigureHost(Test hostTest) - { -#if NETSTANDARD2_0 - if (hostTest == null) { throw new ArgumentNullException(nameof(hostTest)); } -#else - ArgumentNullException.ThrowIfNull(hostTest); -#endif - if (!HasTypes(hostTest.GetType(), typeof(ApplicationTest<,>))) { throw new ArgumentOutOfRangeException(nameof(hostTest), typeof(ApplicationTest<,>), $"{nameof(hostTest)} is not assignable from ApplicationTest."); } - if (this.HasValidState()) { return; } - - Host = ApplicationHostFactory.Create(ConfigureHostCallback); - Configuration = Host.Services.GetRequiredService(); - Environment = Host.Services.GetRequiredService(); - - ConfigureCallback(Configuration, Environment); - - AsyncHostRunnerCallback(Host, CancellationToken.None); - } - - /// - /// Gets or sets the delegate that provides a way to override the before the application is built. - /// - /// The delegate that provides a way to override the . - public Action ConfigureHostCallback { get; set; } -} From 240c1e756c9aff61d9cac78bd9568bbc1f690065 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 14:38:46 +0200 Subject: [PATCH 06/15] =?UTF-8?q?=E2=9C=85=20update=20tests=20for=20Manage?= =?UTF-8?q?dApplicationFixture=20default?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update functional tests to verify that ApplicationTestFactory and WebApplicationTestFactory now use ManagedApplicationFixture and ManagedWebApplicationFixture by default. Tests confirm that entrypoint-owned deferred startup is now the standard behavior. Rename and update legacy test fixtures to work with the new defaults. --- .../DeferredInvalidWebApplicationTest.cs | 6 +- ...cs => ManagedWebApplicationFixtureTest.cs} | 84 +++++++++---------- ...StartupValidationWebApplicationTestTest.cs | 16 ---- .../WebApplicationTestFactoryTest.cs | 16 +--- .../ApplicationTestFactoryTest.cs | 14 +--- .../BootstrapperConsoleApplicationTestTest.cs | 4 +- .../StartupValidationApplicationTestTest.cs | 18 ---- 7 files changed, 51 insertions(+), 107 deletions(-) rename test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/{BlockingManagedWebApplicationFixtureTest.cs => ManagedWebApplicationFixtureTest.cs} (68%) diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/DeferredInvalidWebApplicationTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/DeferredInvalidWebApplicationTest.cs index 72d51e6..74e2cc4 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/DeferredInvalidWebApplicationTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/DeferredInvalidWebApplicationTest.cs @@ -2,9 +2,9 @@ namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; -internal sealed class DeferredInvalidWebApplicationTest : WebApplicationTest> -{ - public DeferredInvalidWebApplicationTest(BlockingManagedWebApplicationFixture hostFixture) : base(true, hostFixture) +internal sealed class DeferredInvalidWebApplicationTest : WebApplicationTest> +{ + public DeferredInvalidWebApplicationTest(ManagedWebApplicationFixture hostFixture) : base(true, hostFixture) { } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/BlockingManagedWebApplicationFixtureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/ManagedWebApplicationFixtureTest.cs similarity index 68% rename from test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/BlockingManagedWebApplicationFixtureTest.cs rename to test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/ManagedWebApplicationFixtureTest.cs index fd65d89..f743c9e 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/BlockingManagedWebApplicationFixtureTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/ManagedWebApplicationFixtureTest.cs @@ -1,42 +1,42 @@ -using System; -using Xunit; -using ModernProgram = Codebelt.Extensions.Xunit.Hosting.Program.App.Program; - -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; - -public class BlockingManagedWebApplicationFixtureTest : Test -{ - public BlockingManagedWebApplicationFixtureTest(ITestOutputHelper output) : base(output) - { - } - - [Fact] - public void ConfigureHost_ShouldThrowArgumentOutOfRangeException_WhenHostTestIsNotWebApplicationTest() - { - var fixture = new BlockingManagedWebApplicationFixture(); - - var ex = Assert.Throws(() => fixture.ConfigureHost(this)); - - Assert.Equal("hostTest", ex.ParamName); - } - - [Fact] - public void ConfigureHost_ShouldThrowInvalidOperationException_WhenEntryPointAssemblyHasNoHost() - { - var fixture = new BlockingManagedWebApplicationFixture(); - var test = new DeferredInvalidWebApplicationTest(fixture); - - fixture.ConfigureCallback = test.Configure; - fixture.ConfigureWebHostCallback = test.Configure; - - Assert.Throws(() => fixture.ConfigureHost(test)); - } - - [Fact] - public void HasValidState_ShouldReturnFalse_WhenFixtureIsUninitialized() - { - var fixture = new BlockingManagedWebApplicationFixture(); - - Assert.False(fixture.HasValidState()); - } -} +using System; +using Xunit; +using ModernProgram = Codebelt.Extensions.Xunit.Hosting.Program.App.Program; + +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class ManagedWebApplicationFixtureTest : Test +{ + public ManagedWebApplicationFixtureTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void ConfigureHost_ShouldThrowArgumentOutOfRangeException_WhenHostTestIsNotWebApplicationTest() + { + var fixture = new ManagedWebApplicationFixture(); + + var ex = Assert.Throws(() => fixture.ConfigureHost(this)); + + Assert.Equal("hostTest", ex.ParamName); + } + + [Fact] + public void ConfigureHost_ShouldThrowInvalidOperationException_WhenEntryPointAssemblyHasNoHost() + { + var fixture = new ManagedWebApplicationFixture(); + var test = new DeferredInvalidWebApplicationTest(fixture); + + fixture.ConfigureCallback = test.Configure; + fixture.ConfigureWebHostCallback = test.Configure; + + Assert.Throws(() => fixture.ConfigureHost(test)); + } + + [Fact] + public void HasValidState_ShouldReturnFalse_WhenFixtureIsUninitialized() + { + var fixture = new ManagedWebApplicationFixture(); + + Assert.False(fixture.HasValidState()); + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/StartupValidationWebApplicationTestTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/StartupValidationWebApplicationTestTest.cs index d1a8f8a..dfbb424 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/StartupValidationWebApplicationTestTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/StartupValidationWebApplicationTestTest.cs @@ -36,22 +36,6 @@ public void ShouldPropagateStartupValidationFailure_WhenUsingManagedWebApplicati Assert.True(validation.Started); } - [Fact] - public void ShouldNotInvokeEntrypoint_WhenUsingBlockingManagedWebApplicationFixture() - { - var missing = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); - var state = new ClassicProgramState(); - var validation = new StartupValidationService(state, missing); - using var fixture = new BlockingManagedWebApplicationFixture(); - using var application = WebApplicationTestFactory.Create( - builder => ConfigureStartupValidation(builder, state, validation), - fixture); - - Assert.NotNull(application.Host.Services); - Assert.False(state.MainInvoked); - Assert.True(validation.Started); - } - private static void ConfigureStartupValidation(IWebHostBuilder builder, ClassicProgramState state, StartupValidationService validation) { builder.ConfigureLogging(logging => logging.ClearProviders()); diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/WebApplicationTestFactoryTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/WebApplicationTestFactoryTest.cs index 2e8a653..f51ff91 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/WebApplicationTestFactoryTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.FunctionalTests/WebApplicationTestFactoryTest.cs @@ -49,7 +49,7 @@ public async Task Create_ShouldBootstrapApplication_WhenEntryPointUsesBootstrapp [Fact] public async Task Create_ShouldBootstrapApplication_WhenEntryPointUsesClassicProgram() { - using var application = WebApplicationTestFactory.Create(hostFixture: new ManagedWebApplicationFixture()); + using var application = WebApplicationTestFactory.Create(); using var client = application.Host.GetTestClient(); var response = await client.GetAsync("/").ConfigureAwait(false); @@ -106,20 +106,6 @@ public async Task Create_ShouldApplyWebHostConfiguration_WhenWebHostSetupIsProvi Assert.Equal("Custom service from WebApplicationTestFactory", serviceBody); } - [Fact] - public async Task Create_ShouldSupportExplicitBlockingFixture() - { - using var application = WebApplicationTestFactory.Create(hostFixture: new BlockingManagedWebApplicationFixture()); - using var client = application.Host.GetTestClient(); - - using var response = await client.GetAsync("/").ConfigureAwait(false); - var body = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - Assert.True(response.IsSuccessStatusCode); - Assert.Equal("Classic Program", body); - Assert.False(application.Host.Services.GetRequiredService().MainInvoked); - } - [Fact] public async Task RunAsync_ShouldReturnResponse_WhenEntryPointUsesModernProgramPattern() { diff --git a/test/Codebelt.Extensions.Xunit.Hosting.FunctionalTests/ApplicationTestFactoryTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.FunctionalTests/ApplicationTestFactoryTest.cs index 08bb557..d7c5329 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.FunctionalTests/ApplicationTestFactoryTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.FunctionalTests/ApplicationTestFactoryTest.cs @@ -51,9 +51,12 @@ public void Create_ShouldStartEntrypoint_WhenUsingManagedApplicationFixture() public void Create_ShouldBootstrapApplication_WhenEntryPointUsesMinimalConsoleProgram() { using var application = ApplicationTestFactory.Create(); + var state = application.Host.Services.GetRequiredService(); Assert.Equal("Development", application.Environment.EnvironmentName); Assert.NotNull(application.Host); + Assert.True(state.MainInvoked); + Assert.True(state.EntrypointStarted); } [Fact] @@ -97,17 +100,6 @@ public void Create_ShouldApplyHostConfiguration_WhenHostSetupIsProvided() Assert.Equal("Configured from ApplicationTestFactory", application.Configuration["Factory:Message"]); } - [Fact] - public void Create_ShouldSupportExplicitBlockingFixture() - { - using var application = ApplicationTestFactory.Create(hostFixture: new BlockingManagedApplicationFixture()); - var state = application.Host.Services.GetRequiredService(); - - Assert.NotNull(application.Host); - Assert.True(state.MainInvoked); - Assert.False(state.EntrypointStarted); - } - [Fact] public void Create_CallerTypeShouldHaveDeclaringTypeOfApplicationTestFactoryTest() { diff --git a/test/Codebelt.Extensions.Xunit.Hosting.FunctionalTests/BootstrapperConsoleApplicationTestTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.FunctionalTests/BootstrapperConsoleApplicationTestTest.cs index 61d0f2d..e151ab2 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.FunctionalTests/BootstrapperConsoleApplicationTestTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.FunctionalTests/BootstrapperConsoleApplicationTestTest.cs @@ -5,9 +5,9 @@ namespace Codebelt.Extensions.Xunit.Hosting; -public class BootstrapperConsoleApplicationTestTest : ApplicationTest> +public class BootstrapperConsoleApplicationTestTest : ApplicationTest> { - public BootstrapperConsoleApplicationTestTest(BlockingManagedApplicationFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) + public BootstrapperConsoleApplicationTestTest(ManagedApplicationFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) { } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.FunctionalTests/StartupValidationApplicationTestTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.FunctionalTests/StartupValidationApplicationTestTest.cs index 42705d7..3fb30f7 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.FunctionalTests/StartupValidationApplicationTestTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.FunctionalTests/StartupValidationApplicationTestTest.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.Logging; using Xunit; using BootstrapperMinimalConsoleProgram = Codebelt.Extensions.Xunit.Hosting.BootstrapperMinimalConsole.App.Program; -using BootstrapperMinimalConsoleState = Codebelt.Extensions.Xunit.Hosting.BootstrapperMinimalConsole.App.BootstrapperMinimalConsoleState; namespace Codebelt.Extensions.Xunit.Hosting; @@ -33,23 +32,6 @@ public void ShouldPropagateStartupValidationFailure_WhenUsingManagedApplicationF Assert.True(validation.Started); } - [Fact] - public void ShouldNotStartHostedServices_WhenUsingBlockingManagedApplicationFixture() - { - var missing = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); - var validation = new StartupValidationService(missing); - using var fixture = new BlockingManagedApplicationFixture(); - using var application = ApplicationTestFactory.Create( - builder => ConfigureStartupValidation(builder, validation), - fixture); - - var state = application.Host.Services.GetRequiredService(); - - Assert.True(state.MainInvoked); - Assert.False(state.EntrypointStarted); - Assert.False(validation.Started); - } - private static void ConfigureStartupValidation(IHostBuilder builder, StartupValidationService validation) { builder.ConfigureLogging(logging => logging.ClearProviders()); From a7b56129fa9e61cf98bcbf07c0bf6658f0ba4163 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 14:39:02 +0200 Subject: [PATCH 07/15] =?UTF-8?q?=F0=9F=93=9D=20update=20api=20documentati?= =?UTF-8?q?on=20for=20v12.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update DocFX API documentation to reflect the removal of BlockingManagedApplicationFixture and BlockingManagedWebApplicationFixture. Update namespace and type pages to emphasize ManagedApplicationFixture and ManagedWebApplicationFixture as the standard fixtures. Clarify entrypoint-owned deferred startup behavior in fixture documentation. --- .../Codebelt.Extensions.Xunit.Hosting.AspNetCore.md | 11 +++++------ .../namespaces/Codebelt.Extensions.Xunit.Hosting.md | 7 +++---- ...Extensions.Xunit.Hosting.ApplicationHostFactory.md | 2 +- ...ing.AspNetCore.ManagedWebApplicationFixture%601.md | 2 +- ...ons.Xunit.Hosting.ManagedApplicationFixture%601.md | 2 +- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/.docfx/api/namespaces/Codebelt.Extensions.Xunit.Hosting.AspNetCore.md b/.docfx/api/namespaces/Codebelt.Extensions.Xunit.Hosting.AspNetCore.md index 9a8a14f..66ee465 100644 --- a/.docfx/api/namespaces/Codebelt.Extensions.Xunit.Hosting.AspNetCore.md +++ b/.docfx/api/namespaces/Codebelt.Extensions.Xunit.Hosting.AspNetCore.md @@ -17,7 +17,7 @@ Complements: [ASP.NET Core integration tests](https://learn.microsoft.com/en-us/ |---|---|---| |Bootstrap an existing ASP.NET Core application for one focused test|`WebApplicationTestFactory.Create`|Returns an owned `IHostTest` whose host exposes the application's `TestServer`, services, configuration, and environment.| |Send one request to an existing application|`WebApplicationTestFactory.RunAsync`|Combines application startup, `HttpClient` creation, request execution, and cleanup in one call.| -|Share an existing application across an xUnit test class|`WebApplicationTest` with `ManagedWebApplicationFixture`|Opt-in entrypoint-owned startup while the fixture exposes `TestServer`.| +|Share an existing application across an xUnit test class|`WebApplicationTest` with `ManagedWebApplicationFixture`|Uses entrypoint-owned startup while the fixture exposes `TestServer`.| |Define services and middleware entirely inside the test|`WebHostTestFactory` or `MinimalWebHostTestFactory`|Builds a purpose-specific in-memory pipeline without loading an application project.| |Attach observers or change state before startup|A `SelfManaged` web fixture|Builds the host and pipeline but leaves startup to the test.| @@ -41,11 +41,10 @@ ASP.NET Core host fixtures follow the same lifecycle naming convention as the ho |---|---| |`Managed`|The fixture owns host creation, configuration and disposal while the application entry point owns startup; test-host consumption starts the deferred host when needed.| |`SelfManaged`|The fixture owns host creation and configuration, but leaves host startup to the test.| -|`BlockingManaged`|The fixture owns the host lifecycle and starts the host synchronously before returning control to the test.| - -For the current minor release, the existing `WebApplicationTestFactory` and blocking fixture paths preserve legacy startup behavior. Use `ManagedWebApplicationFixture` explicitly when the real `Main` method should own startup; fixture setup remains lazy and test-host consumption starts the deferred host. `BlockingManagedWebApplicationFixture` remains available as an obsolete compatibility fixture and should be removed or changed in the next major release. - -`BlockingManagedWebHostFixture` remains the opt-in blocking variant for the lower-level web host fixture family. The application-entry-point fixture is named `BlockingManagedWebApplicationFixture` directly because this API is blocking by convention from its first release. + +`WebApplicationTestFactory` uses `ManagedWebApplicationFixture` by default, so the real application entry point owns startup and fixture setup remains lazy. Use `ManagedWebApplicationFixture` explicitly with `WebApplicationTest` when tests share the application context; use a `SelfManaged` fixture when the test must control startup itself. + +`BlockingManagedWebHostFixture` remains the opt-in blocking variant for the lower-level web host fixture family. It is separate from the application-entry-point fixture, which uses `ManagedWebApplicationFixture` for entrypoint-owned startup. ### Extension Members diff --git a/.docfx/api/namespaces/Codebelt.Extensions.Xunit.Hosting.md b/.docfx/api/namespaces/Codebelt.Extensions.Xunit.Hosting.md index a9d1352..5f22c93 100644 --- a/.docfx/api/namespaces/Codebelt.Extensions.Xunit.Hosting.md +++ b/.docfx/api/namespaces/Codebelt.Extensions.Xunit.Hosting.md @@ -16,7 +16,7 @@ Complements: [xUnit: Shared Context between Tests](https://xunit.net/docs/shared |When you need to|Start with|Why| |---|---|---| |Bootstrap an existing console, worker, or Generic Host application for one test|`ApplicationTestFactory.Create`|Runs the application's entry-point setup and returns an owned `IHostTest` context that the caller disposes.| -|Share an existing application across an xUnit test class|`ApplicationTest` with `ManagedApplicationFixture`|Opt-in entrypoint-owned startup through the new managed fixture while retaining configuration and service access.| +|Share an existing application across an xUnit test class|`ApplicationTest` with `ManagedApplicationFixture`|Uses entrypoint-owned startup while retaining configuration and service access.| |Build a conventional Generic Host entirely inside the test|`HostTestFactory`|Configures `IServiceCollection` and `IHostBuilder` directly without requiring an application entry point.| |Build with the modern `IHostApplicationBuilder` model|`MinimalHostTestFactory`|Keeps minimal-host tests focused on services and application-builder configuration.| |Configure the host now but decide when it starts|A `SelfManaged` fixture|Leaves startup under test control so observers and pre-start assertions can be attached first.| @@ -29,9 +29,8 @@ Host fixtures follow a lifecycle naming convention: |---|---| |`Managed`|The fixture owns host creation, configuration and disposal while the application entry point owns startup; test-host consumption starts the deferred host when needed.| |`SelfManaged`|The fixture owns host creation and configuration, but leaves host startup to the test.| -|`BlockingManaged`|The fixture owns the host lifecycle and starts the host synchronously before returning control to the test.| - -For the current minor release, the existing `ApplicationTestFactory` and blocking fixture paths preserve legacy startup behavior. Use `ManagedApplicationFixture` explicitly when the real `Main` method should own startup; fixture setup remains lazy and test-host consumption starts the deferred host. `BlockingManagedApplicationFixture` remains available as an obsolete compatibility fixture and should be removed or changed in the next major release. + +`ApplicationTestFactory` uses `ManagedApplicationFixture` by default, so the real application entry point owns startup and fixture setup remains lazy. Use `ManagedApplicationFixture` explicitly with `ApplicationTest` when tests share the application context; use a `SelfManaged` fixture when the test must control startup itself. ### Extension Members diff --git a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.ApplicationHostFactory.md b/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.ApplicationHostFactory.md index 9bf375d..afe7e9f 100644 --- a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.ApplicationHostFactory.md +++ b/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.ApplicationHostFactory.md @@ -4,7 +4,7 @@ example: - *content --- -The test project references a worker application's entry-point assembly. `ApplicationHostFactory.Create` preserves the current minor-release compatibility path, including direct use of an application's `CreateHostBuilder` when it is available. When the application entry point should own startup, pass `ManagedApplicationFixture` to `ApplicationTestFactory.Create`; the fixture opts into the deferred path without changing the existing factory method signature. The compatibility path is intentionally retained until it can be removed or changed in the next major release. Because this lower-level factory returns the host directly, the caller still owns disposal. +The test project references a worker application's entry-point assembly. `ApplicationHostFactory.Create` preserves the compatibility path, including direct use of an application's `CreateHostBuilder` when it is available. `ApplicationTestFactory.Create` uses `ManagedApplicationFixture` by default when the application entry point should own startup; pass an explicit fixture when a shared test context needs to customize its lifecycle. Because this lower-level factory returns the host directly, the caller still owns disposal. ```csharp using Codebelt.Extensions.Xunit.Hosting; diff --git a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.AspNetCore.ManagedWebApplicationFixture%601.md b/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.AspNetCore.ManagedWebApplicationFixture%601.md index 4f1edf5..4926258 100644 --- a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.AspNetCore.ManagedWebApplicationFixture%601.md +++ b/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.AspNetCore.ManagedWebApplicationFixture%601.md @@ -4,7 +4,7 @@ example: - *content --- -Use `ManagedWebApplicationFixture` when an xUnit class fixture should exercise an ASP.NET Core application's real entry point and let that entry point start the in-memory server. Derive the test from `WebApplicationTest` and pass the fixture to its base constructor so the base class initializes the fixture through `ConfigureHost` before the test reads `Server`. This is an opt-in path for the current minor release. Fixture setup remains lazy; consuming the test host starts the deferred host, after which the test can create a client from the exposed `TestServer` and verify the application's endpoint behavior. The legacy blocking path is retained for compatibility until it can be removed or changed in the next major release. +Use `ManagedWebApplicationFixture` when an xUnit class fixture should exercise an ASP.NET Core application's real entry point and let that entry point start the in-memory server. Derive the test from `WebApplicationTest` and pass the fixture to its base constructor so the base class initializes the fixture through `ConfigureHost` before the test reads `Server`. Fixture setup remains lazy; consuming the test host starts the deferred host, after which the test can create a client from the exposed `TestServer` and verify the application's endpoint behavior. `WebApplicationTestFactory` uses this fixture by default. ```csharp using System.Threading.Tasks; diff --git a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.ManagedApplicationFixture%601.md b/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.ManagedApplicationFixture%601.md index 2fab889..65cde41 100644 --- a/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.ManagedApplicationFixture%601.md +++ b/.docfx/api/types/Codebelt.Extensions.Xunit.Hosting.ManagedApplicationFixture%601.md @@ -4,7 +4,7 @@ example: - *content --- -Use `ManagedApplicationFixture` when an xUnit class fixture should exercise the application's real entry point and let that entry point start the host. Derive the test from `ApplicationTest` and pass the fixture to its base constructor so the base class initializes the fixture through `ConfigureHost` before the test reads `Host`. This is an opt-in path for the current minor release. Fixture setup remains lazy; accessing the test host starts the deferred host and surfaces startup failures at the point the test consumes it. The legacy blocking path is retained for compatibility until it can be removed or changed in the next major release. +Use `ManagedApplicationFixture` when an xUnit class fixture should exercise the application's real entry point and let that entry point start the host. Derive the test from `ApplicationTest` and pass the fixture to its base constructor so the base class initializes the fixture through `ConfigureHost` before the test reads `Host`. Fixture setup remains lazy; accessing the test host starts the deferred host and surfaces startup failures at the point the test consumes it. `ApplicationTestFactory` uses this fixture by default. ```csharp using Codebelt.Extensions.Xunit.Hosting; From 86887785565c3860acfdaab83d89b7ae99200944 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 14:39:18 +0200 Subject: [PATCH 08/15] =?UTF-8?q?=F0=9F=93=A6=20update=20package=20release?= =?UTF-8?q?=20notes=20and=20readmes=20for=20v12.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update NuGet package release notes across all packages to document v12.0.0 changes: xunit framework upgrade to v4.0.0, dependency version updates, removal of BlockingManagedApplicationFixture, and improvements to ApplicationTestFactory defaults. Update README.md files to reflect current API and best practices. --- .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 12 ++++++++++++ .../README.md | 2 +- .../PackageReleaseNotes.txt | 12 ++++++++++++ .nuget/Codebelt.Extensions.Xunit.Hosting/README.md | 2 +- .../PackageReleaseNotes.txt | 6 ++++++ 6 files changed, 38 insertions(+), 2 deletions(-) diff --git a/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt index 0dc48b6..8e209da 100644 --- a/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 12.0.0 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED xunit framework suite from v3.2.2 to v4.0.0 and upgraded supporting dependencies: Codebelt.Bootstrapper packages to v5.2.1, Codebelt.Extensions.BenchmarkDotNet.Console to v1.3.3, and Microsoft.NET.Test.Sdk to v18.9.0 + Version: 11.2.1 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt index 4920aac..c62289d 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt @@ -1,3 +1,15 @@ +Version: 12.0.0 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED xunit framework suite from v3.2.2 to v4.0.0 and upgraded supporting dependencies: Codebelt.Bootstrapper packages to v5.2.1, Codebelt.Extensions.BenchmarkDotNet.Console to v1.3.3, and Microsoft.NET.Test.Sdk to v18.9.0 + +# Breaking Changes +- REMOVED BlockingManagedWebApplicationFixture{TEntryPoint}; use ManagedWebApplicationFixture{TEntryPoint} instead + +# Improvements +- CHANGED WebApplicationTestFactory to use ManagedWebApplicationFixture{TEntryPoint} as its default fixture + Version: 11.2.1 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/README.md b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/README.md index 9808463..b66624b 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/README.md +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/README.md @@ -15,7 +15,7 @@ The `Codebelt.Extensions.Xunit.Hosting.AspNetCore` namespace contains types that `WebApplicationTestFactory.Create` is a lightweight alternative for focused integration tests that prefer inline `IWebHostBuilder` customization and Codebelt's common `IHostTest` model. It is not a drop-in replacement for [WebApplicationFactory](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.testing.webapplicationfactory-1): use Microsoft's factory when reusable derived factories, `CreateClient` options, `WithWebHostBuilder`, or MVC content-root conventions are central to the test suite. -For the current minor release, the existing factory and blocking fixture paths preserve their legacy startup behavior. Use `ManagedWebApplicationFixture` explicitly when the application's `Main` method should own startup and the deferred `TestServer` should start when the test host is consumed. `BlockingManagedWebApplicationFixture` remains available as an obsolete compatibility option until it can be removed or changed in the next major release. +`WebApplicationTestFactory` uses `ManagedWebApplicationFixture` by default, so the application's `Main` method owns startup and the deferred `TestServer` starts when the test host is consumed. Use `ManagedWebApplicationFixture` explicitly with `WebApplicationTest` when tests share the application context. For lower-level web-host tests that require synchronous startup, use the separate `BlockingManagedWebHostFixture`. More documentation available at our documentation site: diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt index 6aa6be6..b2710e1 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt @@ -1,3 +1,15 @@ +Version: 12.0.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED xunit framework suite from v3.2.2 to v4.0.0 and upgraded supporting dependencies: Codebelt.Bootstrapper packages to v5.2.1, Codebelt.Extensions.BenchmarkDotNet.Console to v1.3.3, and Microsoft.NET.Test.Sdk to v18.9.0 + +# Breaking Changes +- REMOVED BlockingManagedApplicationFixture{TEntryPoint}; use ManagedApplicationFixture{TEntryPoint} instead + +# Improvements +- CHANGED ApplicationTestFactory to use ManagedApplicationFixture{TEntryPoint} as its default fixture + Version: 11.2.1 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting/README.md b/.nuget/Codebelt.Extensions.Xunit.Hosting/README.md index 02b5d12..3953423 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting/README.md +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting/README.md @@ -13,7 +13,7 @@ It is, by heart, free, flexible and built to extend and boost your agile codebel The `Codebelt.Extensions.Xunit.Hosting` namespace contains types that provides a uniform way of doing unit testing that is used in conjunction with Microsoft Dependency Injection. The namespace relates to the `Xunit.Abstractions` namespace. -Use `ApplicationTestFactory.Create` for a focused integration test against an existing console, worker or Generic Host application's `Program` assembly. It brings the entry-point testing pattern commonly associated with ASP.NET Core to the rest of the .NET application stack. For the current minor release, existing factory and blocking fixture paths preserve their legacy startup behavior; use `ManagedApplicationFixture` explicitly when the application's `Main` method should own startup and the deferred host should start when the test host is consumed. `BlockingManagedApplicationFixture` remains as an obsolete compatibility option until it can be removed or changed in the next major release. +Use `ApplicationTestFactory.Create` for a focused integration test against an existing console, worker or Generic Host application's `Program` assembly. It brings the entry-point testing pattern commonly associated with ASP.NET Core to the rest of the .NET application stack. The factory uses `ManagedApplicationFixture` by default, so the application's `Main` method owns startup and the deferred host starts when the test host is consumed. Use `ManagedApplicationFixture` explicitly with `ApplicationTest` when tests share the application context. More documentation available at our documentation site: diff --git a/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt index ce20004..416936a 100644 --- a/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 12.0.0 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED xunit framework suite from v3.2.2 to v4.0.0 and upgraded supporting dependencies: Codebelt.Bootstrapper packages to v5.2.1, Codebelt.Extensions.BenchmarkDotNet.Console to v1.3.3, and Microsoft.NET.Test.Sdk to v18.9.0 + Version: 11.2.1 Availability: .NET 10, .NET 9 and .NET Standard 2.0 From f9d9b71f679e8223dc0ca7502c00985febf88a88 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 14:39:35 +0200 Subject: [PATCH 09/15] =?UTF-8?q?=F0=9F=92=AC=20update=20changelog=20and?= =?UTF-8?q?=20contribution=20guidelines=20for=20v12.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add v12.0.0 release entry to CHANGELOG.md documenting breaking changes, improvements, and ALM updates. Update CONTRIBUTING.md with guidance for v12.0.0 development. Breaking change: removal of BlockingManagedApplicationFixture and BlockingManagedWebApplicationFixture types. Improvement: ApplicationTestFactory now uses ManagedApplicationFixture as the default fixture. --- .github/CONTRIBUTING.md | 103 +++++++++++++++++++++++++--------------- CHANGELOG.md | 29 ++++++++++- 2 files changed, 93 insertions(+), 39 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index fd26a57..a30dbed 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,52 +1,79 @@ -# Contributing to `Extensions for xUnit API by Codebelt` -When contributing to this repository, please first discuss the change you wish to make via issue, -email, or any other method with the owners of this repository before making a change. +# Contributing to Extensions for xUnit API by Codebelt -Please note we have a code of conduct, please follow it in all your interactions with the project. +This repository is part of the Codebelt .NET library estate. The instructions below describe the current checkout and its CI contract. Please keep changes focused and preserve the shared Codebelt build skeleton unless a deliberate policy change is being made. -## Code of Conduct -Please review our [code of conduct](CODE_OF_CONDUCT.md). +## Before you start -## Our Development Process -We use `trunk` based branching model that is aligned with todays DevSecOps practices. -All new features and/or fixes are merged into the `main` branch by creating a Pull Request. +- Read the repository `README.md` and open an issue before starting a non-trivial feature or behavioral change. +- Use an installed .NET SDK that can build the target frameworks listed below. This repository currently targets: **net10.0, net48, net9.0, netstandard2.0**. +- The solution is `Codebelt.Extensions.Xunit.slnx`. Central package versions are maintained in `Directory.Packages.props`. +- The shared build behavior is in `Directory.Build.props` and `Directory.Build.targets`; repository-specific TFMs, package references and metadata remain local to this library. -## Pull Requests -We actively welcome your pull requests. +## Repository shape -1. Fork the repo and create your branch from `main` -2. If you've added code that should be tested, add tests (DO follow [Microsoft Engineering Guidelines](https://github.com/dotnet/aspnetcore/wiki/Engineering-guidelines)) -3. Any changes or additions requires documentation in the form of documenting public members -4. Ensure that all existing as well as new test passes -5. Issue that pull request with a big and heartful thanks for contributing +- `src/` contains production projects. +- `test/` contains xUnit v3 test projects. +- `Codebelt.Extensions.Xunit.slnx` is the solution used for local development. +- `.github/workflows/ci-pipeline.yml` is the CI workflow and the authority for the test matrix. +- `testenvironments.json` declares the supported `WSL-Ubuntu` and `Docker-Ubuntu` test environments. -## Issues -We use GitHub issues to track public bugs. Please ensure your description is -clear and has sufficient instructions to be able to reproduce the issue. +## Build + +Restore and build the solution from the repository root: + +```powershell +dotnet restore "Codebelt.Extensions.Xunit.slnx" +dotnet build "Codebelt.Extensions.Xunit.slnx" --configuration Release --no-restore +``` + +CI builds both Debug and Release configurations. A clean build should complete before opening a pull request. + +## Test + +Run tests one project at a time so a failing or hanging project is attributable. This mirrors the CI matrix; it does not silently turn skipped integration tests into passing tests. + +```powershell +$testProjects = Get-ChildItem test -Filter *.csproj -Recurse +foreach ($project in $testProjects) { + dotnet test $project.FullName --configuration Release --no-restore +} +``` + +The CI test plan currently runs **5** project(s) and excludes **0** project(s). The workflow also has an optional macOS test job. + +## Integration and infrastructure -## Coding Guidelines -* Please follow [Framework Design Guidelines](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/) -* Please follow SOLID principles -* Please follow [Microsoft Engineering Guidelines](https://github.com/dotnet/aspnetcore/wiki/Engineering-guidelines) +- `WSL-Ubuntu` — WSL distribution `Ubuntu-24.04`. +- `Docker-Ubuntu` — Docker image `codebeltnet/ubuntu-testrunner:8-9-10-11`. -## Manifesto -As aspiring Software Craftsmen we are raising the bar of professional software development by practicing it and helping others learn the craft. +This repository has no repository-local `docker-compose.yml` service dependency in the current checkout. +Use the environments declared in `testenvironments.json` when you need the estate test runner. -Through this work we have come to value: +## Package and documentation -* Not only working software, -but also well-crafted software -* Not only responding to change, -but also steadily adding value -* Not only individuals and interactions, -but also a community of professionals -* Not only customer collaboration, -but also productive partnerships +Create packages using the same solution and Release configuration: -That is, in pursuit of the items on the left we have found the items on the right to be indispensable. +```powershell +dotnet pack "Codebelt.Extensions.Xunit.slnx" --configuration Release --no-restore +``` -[Manifesto for Software Craftsmanship](https://manifesto.softwarecraftsmanship.org/) is the originator of this text. +Package-specific release notes live under `.nuget//PackageReleaseNotes.txt` and package README files live beside them. `Directory.Build.targets` imports the release notes during packing. Public API changes also require XML documentation updates; DocFX documentation is built by the repository automation. + +## Pull requests + +1. Create or join an issue before substantial work, then fork the repository and create a branch from `main`. +2. Add or update focused tests and public API documentation where applicable. +3. Run restore, build, and the relevant per-project tests locally. +4. Keep the pull request small, explain the behavior change and validation performed, and wait for the CI checks to pass. + +## Issues + +Include the affected project, target framework, operating system, SDK version, exact command, expected result, actual result, and a minimal reproduction. Identify whether the behavior differs between local Windows/WSL, Docker-Ubuntu and GitHub Actions. + +## Coding guidelines + +Follow the existing style, the Framework Design Guidelines, the repository `.editorconfig`, and the shared Codebelt conventions. Do not make unrelated formatting or infrastructure changes in a feature pull request. ## License -By contributing to `Extensions for xUnit API by Codebelt`, you agree that your contributions will be licensed -under the MIT license. \ No newline at end of file + +By contributing to Extensions for xUnit API by Codebelt, you agree that your contributions will be licensed under the MIT license. diff --git a/CHANGELOG.md b/CHANGELOG.md index 4801550..dca7ea1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,32 @@ For more details, please refer to `PackageReleaseNotes.txt` on a per assembly ba > [!NOTE] > Changelog entries prior to version 8.4.0 was migrated from previous versions of Cuemon.Extensions.Xunit, Cuemon.Extensions.Xunit.Hosting, and Cuemon.Extensions.Xunit.Hosting.AspNetCore. +## [12.0.0] - 2026-08-24 + +This is a major release driven by the upgrade to xUnit v4.0.0, reflecting the decision to bump this library's major version in alignment with the xUnit framework's major release after careful consideration. The xUnit v4 upgrade introduces breaking changes to the testing framework that may require updates to existing test code. + +> [!WARNING] +> **xUnit v4 Breaking Changes:** This release upgrades to xUnit v4.0.0, which contains breaking changes to the xUnit testing framework. Before upgrading, please review the [xUnit v4.0.0 release notes](https://xunit.net/releases/v3/4.0.0) for details on required code updates, API removals, and migration guidance. Pay special attention to changes in assertion methods, fixture behavior, and test collection definitions. + +### Breaking Changes + +- Removed `BlockingManagedApplicationFixture` and `BlockingManagedWebApplicationFixture`; use `ManagedApplicationFixture` and `ManagedWebApplicationFixture` instead. + +### Changed + +- Upgraded xunit.v3, xunit.v3.assert, xunit.v3.extensibility.core, and xunit.v3.runner.console from v3.2.2 to v4.0.0, +- Upgraded xunit.runner.visualstudio from v3.1.5 to v4.0.0 for Visual Studio test explorer integration, +- Upgraded Codebelt.Bootstrapper.Console, Codebelt.Bootstrapper.Web, and Codebelt.Bootstrapper.Worker from v5.2.0 to v5.2.1, +- Upgraded Codebelt.Extensions.BenchmarkDotNet.Console from v1.3.2 to v1.3.3, +- Upgraded Microsoft.NET.Test.Sdk from v18.8.1 to v18.9.0 for improved compatibility with xUnit v4, +- Consolidated Docker test environments to a unified ubuntu-testrunner:8-9-10-11 image for improved maintainability across .NET 8, 9, 10, and 11, +- Updated DocFX base image to nginx 1.31-alpine and bumped DocFX from v2.78.4 to v2.78.5, +- Removed obsolete analyzer rules (CA1200 for cref tag prefix usage and IDE0330 for System.Threading.Lock) from editor configuration that are no longer relevant. + +### Fixed + +- Fixed typo in .editorconfig IDE0036 comment documentation. + ## [11.2.1] - 2026-08-12 This is a patch release providing dependency updates to the latest compatible versions across all supported target frameworks. @@ -489,7 +515,8 @@ This major release is first and foremost focused on ironing out any wrinkles tha -[Unreleased]: https://github.com/codebeltnet/xunit/compare/v11.2.1...HEAD +[Unreleased]: https://github.com/codebeltnet/xunit/compare/v12.0.0...HEAD +[12.0.0]: https://github.com/codebeltnet/xunit/compare/v11.2.1...v12.0.0 [11.2.1]: https://github.com/codebeltnet/xunit/compare/v11.2.0...v11.2.1 [11.2.0]: https://github.com/codebeltnet/xunit/compare/v11.1.2...v11.2.0 [11.1.2]: https://github.com/codebeltnet/xunit/compare/v11.1.1...v11.1.2 From 3b6d95c9d9b8c65426ca3577b9be3929715de785 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 14:40:00 +0200 Subject: [PATCH 10/15] =?UTF-8?q?=F0=9F=93=9D=20clarify=20ApplicationHostF?= =?UTF-8?q?actory=20remarks=20for=20v12.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update XML documentation remarks for ApplicationHostFactory to reflect that the deferred entry-point path is now the standard behavior through managed application fixtures. Remove deprecation warnings about the legacy path as v12.0.0 makes this the default. --- .../ApplicationHostFactory.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Codebelt.Extensions.Xunit.Hosting/ApplicationHostFactory.cs b/src/Codebelt.Extensions.Xunit.Hosting/ApplicationHostFactory.cs index d77e2a5..3948fc6 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/ApplicationHostFactory.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/ApplicationHostFactory.cs @@ -16,8 +16,7 @@ public static class ApplicationHostFactory /// The delegate that provides a way to override the before the application is built. /// A built instance. /// - /// For compatibility, applications that expose CreateHostBuilder(string[]) are built through that factory. Applications that do not expose the legacy factory use the deferred entry-point path. - /// The legacy path and its wrapper behavior are retained for the current minor release; only the managed application fixtures opt into entrypoint-owned deferred startup. The legacy path should be removed or changed in the next major release. + /// For compatibility, applications that expose CreateHostBuilder(string[]) are built through that factory. Applications that do not expose the legacy factory use the deferred entry-point path. Managed application fixtures use the deferred entry-point path so the application owns startup. /// /// /// The entry point assembly does not expose a supported application host. @@ -35,8 +34,7 @@ public static IHost Create(Action configureHost) wher /// A value indicating whether the entry point should be stopped after the host is built. /// A built instance. /// - /// For compatibility, applications that expose CreateHostBuilder(string[]) are built through that factory and the value is ignored for that path. - /// The legacy path and its wrapper behavior are retained for the current minor release; only the managed application fixtures opt into entrypoint-owned deferred startup. The legacy path should be removed or changed in the next major release. + /// For compatibility, applications that expose CreateHostBuilder(string[]) are built through that factory and the value is ignored for that path. Managed application fixtures use the deferred entry-point path so the application owns startup. /// /// /// The entry point assembly does not expose a supported application host. From 44c927205eb09507ce68d71c02dca431c2118fcd Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 16:28:19 +0200 Subject: [PATCH 11/15] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20opt=20into=20microso?= =?UTF-8?q?ft.testing.platform=20for=20xunit=20v4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable the Microsoft.Testing.Platform dotnet test experience for xUnit v4 on .NET 10 and later, with native TRX and coverage reporting support via Microsoft.Testing.Extensions.CodeCoverage. --- Directory.Build.props | 1 + Directory.Packages.props | 1 + global.json | 5 +++++ 3 files changed, 7 insertions(+) create mode 100644 global.json diff --git a/Directory.Build.props b/Directory.Build.props index c64d6d6..41a8181 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -88,6 +88,7 @@ + diff --git a/Directory.Packages.props b/Directory.Packages.props index f7ca117..11d986b 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -14,6 +14,7 @@ + diff --git a/global.json b/global.json new file mode 100644 index 0000000..3140116 --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "test": { + "runner": "Microsoft.Testing.Platform" + } +} From f45fd3b2920542dc3e1f18f96e8bb344f5deb046 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 16:28:31 +0200 Subject: [PATCH 12/15] =?UTF-8?q?=F0=9F=92=AC=20document=20mtp=20migration?= =?UTF-8?q?=20and=20coverage=20setup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add IMPORTANT note in v12.0.0 release describing the CI migration path for xUnit v4 users upgrading to .NET 10+ with MTP support, and document the code coverage fix in the Fixed section. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dca7ea1..7b76c08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ This is a major release driven by the upgrade to xUnit v4.0.0, reflecting the de > [!WARNING] > **xUnit v4 Breaking Changes:** This release upgrades to xUnit v4.0.0, which contains breaking changes to the xUnit testing framework. Before upgrading, please review the [xUnit v4.0.0 release notes](https://xunit.net/releases/v3/4.0.0) for details on required code updates, API removals, and migration guidance. Pay special attention to changes in assertion methods, fixture behavior, and test collection definitions. +> [!IMPORTANT] +> **CI migration for xUnit v4 on .NET 10 and later:** CI users upgrading to this release must add a root `global.json` opting into [Microsoft.Testing.Platform](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-dotnet-test) and update VSTest-specific test, result, and coverage arguments to their MTP-native equivalents. Add [`Microsoft.Testing.Extensions.CodeCoverage`](https://learn.microsoft.com/en-us/dotnet/core/testing/microsoft-testing-platform-extensions-code-coverage) to test projects when collecting coverage through MTP. Repositories that remain on pre-v4 xUnit or do not opt into MTP continue using the existing CI path. + ### Breaking Changes - Removed `BlockingManagedApplicationFixture` and `BlockingManagedWebApplicationFixture`; use `ManagedApplicationFixture` and `ManagedWebApplicationFixture` instead. @@ -31,6 +34,7 @@ This is a major release driven by the upgrade to xUnit v4.0.0, reflecting the de ### Fixed +- Fixed CI test execution for xUnit v4 on .NET 10 and later by opting into the Microsoft.Testing.Platform `dotnet test` experience and using its native TRX and coverage reporting, - Fixed typo in .editorconfig IDE0036 comment documentation. ## [11.2.1] - 2026-08-12 From 01b370528784ccd4b19f871ce23722212dd57d27 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 18:49:03 +0200 Subject: [PATCH 13/15] =?UTF-8?q?=F0=9F=90=9B=20fix=20deferred=20host=20st?= =?UTF-8?q?artup=20completion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register the ApplicationStarted callback before the deferred host is released so StartAsync waits on the correct completion signal. This preserves lazy startup ordering for managed fixtures without reintroducing the legacy registration race. --- .../Internal/DeferredHostBuilder.cs | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/Codebelt.Extensions.Xunit.Hosting/Internal/DeferredHostBuilder.cs b/src/Codebelt.Extensions.Xunit.Hosting/Internal/DeferredHostBuilder.cs index 61db5c7..936d37b 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/Internal/DeferredHostBuilder.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/Internal/DeferredHostBuilder.cs @@ -41,10 +41,12 @@ public IHost Build() var capture = (ProgramHostFactoryResolver.HostCapture)_hostFactory(args.ToArray()); var host = capture.Host; + // Register before the entry point is released from HostBuilt so its later ApplicationStarted callbacks run before this completion signal. + var startedRegistration = capture.ApplicationLifetime.ApplicationStarted.Register(() => _hostStarted.TrySetResult(null)); // Preserve the legacy wrapper for ApplicationHostFactory fallback callers. Only managed application fixtures opt into the marker that HostTest uses for lazy startup. var deferredHost = _entrypointOwned - ? new EntrypointOwnedDeferredHost(host, _hostStarted, capture) - : new DeferredHost(host, _hostStarted, capture); + ? new EntrypointOwnedDeferredHost(host, _hostStarted, capture, startedRegistration) + : new DeferredHost(host, _hostStarted, capture, startedRegistration); if (!_entrypointOwned) { @@ -119,27 +121,29 @@ public void Dispose() private class DeferredHost : IHost, IAsyncDisposable { private readonly IHost _host; - private readonly IHostApplicationLifetime _applicationLifetime; private readonly ProgramHostFactoryResolver.HostCapture _capture; private readonly TaskCompletionSource _hostStarted; + private readonly CancellationTokenRegistration _startedRegistration; - public DeferredHost(IHost host, TaskCompletionSource hostStarted, ProgramHostFactoryResolver.HostCapture capture) + public DeferredHost(IHost host, TaskCompletionSource hostStarted, ProgramHostFactoryResolver.HostCapture capture, CancellationTokenRegistration startedRegistration) { _host = host; - _applicationLifetime = capture.ApplicationLifetime; _capture = capture; _hostStarted = hostStarted; + _startedRegistration = startedRegistration; } public IServiceProvider Services => _host.Services; public void Dispose() { + _startedRegistration.Dispose(); _host.Dispose(); } public async ValueTask DisposeAsync() { + _startedRegistration.Dispose(); if (_host is IAsyncDisposable disposable) { await disposable.DisposeAsync().ConfigureAwait(false); @@ -151,15 +155,7 @@ public async ValueTask DisposeAsync() public async Task StartAsync(CancellationToken cancellationToken = default) { - if (_hostStarted.Task.IsCompleted) - { - await _hostStarted.Task.ConfigureAwait(false); - return; - } - using var registration = cancellationToken.Register(() => _hostStarted.TrySetCanceled()); - using var startedRegistration = _applicationLifetime.ApplicationStarted.Register(() => _hostStarted.TrySetResult(null)); - await _hostStarted.Task.ConfigureAwait(false); } @@ -176,7 +172,7 @@ public void ReleaseEntrypoint() private sealed class EntrypointOwnedDeferredHost : DeferredHost, IDeferredHost { - public EntrypointOwnedDeferredHost(IHost host, TaskCompletionSource hostStarted, ProgramHostFactoryResolver.HostCapture capture) : base(host, hostStarted, capture) + public EntrypointOwnedDeferredHost(IHost host, TaskCompletionSource hostStarted, ProgramHostFactoryResolver.HostCapture capture, CancellationTokenRegistration startedRegistration) : base(host, hostStarted, capture, startedRegistration) { } } From eecb707d069f5c0546af3c4af7b582dffd872d6f Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 19:31:08 +0200 Subject: [PATCH 14/15] =?UTF-8?q?=F0=9F=93=A6=20update=20package=20release?= =?UTF-8?q?=20notes=20for=20v12.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added bug fix documentation for deferred host startup completion fix to both Codebelt.Extensions.Xunit.Hosting and Codebelt.Extensions.Xunit.Hosting.AspNetCore package release notes. --- .../PackageReleaseNotes.txt | 3 +++ .../Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt index c62289d..c2e7dcc 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt @@ -10,6 +10,9 @@ Availability: .NET 10 and .NET 9 # Improvements - CHANGED WebApplicationTestFactory to use ManagedWebApplicationFixture{TEntryPoint} as its default fixture +# Bug Fixes +- FIXED deferred host startup completion in managed fixtures by registering the ApplicationStarted callback before releasing the host, ensuring StartAsync waits on the correct completion signal + Version: 11.2.1 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt index b2710e1..7390a79 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt @@ -10,6 +10,9 @@ Availability: .NET 10, .NET 9 and .NET Standard 2.0 # Improvements - CHANGED ApplicationTestFactory to use ManagedApplicationFixture{TEntryPoint} as its default fixture +# Bug Fixes +- FIXED deferred host startup completion in managed fixtures by registering the ApplicationStarted callback before releasing the host, ensuring StartAsync waits on the correct completion signal + Version: 11.2.1 Availability: .NET 10, .NET 9 and .NET Standard 2.0 From 6ef6b78eeccb648cc150f121b087d53205664f70 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Mon, 24 Aug 2026 19:31:19 +0200 Subject: [PATCH 15/15] =?UTF-8?q?=F0=9F=92=AC=20update=20changelog=20for?= =?UTF-8?q?=20v12.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructured changelog sections to reorganize breaking changes into Added/Changed/Removed/Fixed categories, improving clarity on the major xUnit v4 migration and managed fixture improvements. --- CHANGELOG.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b76c08..1605dbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,9 +17,11 @@ This is a major release driven by the upgrade to xUnit v4.0.0, reflecting the de > [!IMPORTANT] > **CI migration for xUnit v4 on .NET 10 and later:** CI users upgrading to this release must add a root `global.json` opting into [Microsoft.Testing.Platform](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-dotnet-test) and update VSTest-specific test, result, and coverage arguments to their MTP-native equivalents. Add [`Microsoft.Testing.Extensions.CodeCoverage`](https://learn.microsoft.com/en-us/dotnet/core/testing/microsoft-testing-platform-extensions-code-coverage) to test projects when collecting coverage through MTP. Repositories that remain on pre-v4 xUnit or do not opt into MTP continue using the existing CI path. -### Breaking Changes +### Added -- Removed `BlockingManagedApplicationFixture` and `BlockingManagedWebApplicationFixture`; use `ManagedApplicationFixture` and `ManagedWebApplicationFixture` instead. +- Global opt-in configuration via `global.json` to enable Microsoft.Testing.Platform `dotnet test` experience for xUnit v4 on .NET 10 and later, +- `Microsoft.Testing.Extensions.CodeCoverage` dependency to support native TRX and coverage reporting through MTP, +- `.gitattributes` file for consistent line-ending handling and merge strategies across platforms to reduce merge conflicts. ### Changed @@ -28,14 +30,19 @@ This is a major release driven by the upgrade to xUnit v4.0.0, reflecting the de - Upgraded Codebelt.Bootstrapper.Console, Codebelt.Bootstrapper.Web, and Codebelt.Bootstrapper.Worker from v5.2.0 to v5.2.1, - Upgraded Codebelt.Extensions.BenchmarkDotNet.Console from v1.3.2 to v1.3.3, - Upgraded Microsoft.NET.Test.Sdk from v18.8.1 to v18.9.0 for improved compatibility with xUnit v4, +- `ApplicationTestFactory` and `WebApplicationTestFactory` now default to `ManagedApplicationFixture` and `ManagedWebApplicationFixture` for entrypoint-owned deferred startup behavior, - Consolidated Docker test environments to a unified ubuntu-testrunner:8-9-10-11 image for improved maintainability across .NET 8, 9, 10, and 11, - Updated DocFX base image to nginx 1.31-alpine and bumped DocFX from v2.78.4 to v2.78.5, - Removed obsolete analyzer rules (CA1200 for cref tag prefix usage and IDE0330 for System.Threading.Lock) from editor configuration that are no longer relevant. +### Removed + +- `BlockingManagedApplicationFixture` and `BlockingManagedWebApplicationFixture`; migrate to `ManagedApplicationFixture` and `ManagedWebApplicationFixture` which are now the default fixtures in the factory methods. + ### Fixed -- Fixed CI test execution for xUnit v4 on .NET 10 and later by opting into the Microsoft.Testing.Platform `dotnet test` experience and using its native TRX and coverage reporting, -- Fixed typo in .editorconfig IDE0036 comment documentation. +- Deferred host startup completion in managed fixtures by registering the ApplicationStarted callback before releasing the host, ensuring StartAsync waits on the correct completion signal without introducing the legacy registration race, +- Typo in .editorconfig IDE0036 comment documentation. ## [11.2.1] - 2026-08-12