Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
108ba79
✨ add ApplicationHostFactory and hosting test base classes
gimlichael Jun 4, 2026
b0d4ed2
✨ add WebApplicationTest and web application fixture abstractions
gimlichael Jun 4, 2026
3e7c395
🧪 add bootstrapper reference applications
gimlichael Jun 4, 2026
8edd096
⬆️ upgrade dependencies to latest compatible versions
gimlichael Jun 4, 2026
2657340
🔧 update solution and project configuration
gimlichael Jun 4, 2026
9cb9961
💬 document 11.1.0 release for hosting packages
gimlichael Jun 4, 2026
b93af31
💬 add 11.1.0 release notes
aicia-bot Jun 4, 2026
ce46188
💥 remove legacy managed fixture implementations
gimlichael Jun 5, 2026
c2862bc
✨ introduce factory-based testing for generic host
gimlichael Jun 5, 2026
016fcb1
✨ introduce factory-based testing for ASP.NET Core
gimlichael Jun 5, 2026
2ec0d19
🔥 remove obsolete bootstrapper entry point tests
gimlichael Jun 5, 2026
989d49c
✅ update hosting tests to use factory patterns
gimlichael Jun 5, 2026
6652e2a
✅ add comprehensive test coverage for new factory patterns
gimlichael Jun 5, 2026
2802916
📝 update API namespace documentation
gimlichael Jun 5, 2026
bf2763b
📝 update repo guidelines for API documentation
gimlichael Jun 5, 2026
e9c603a
💬 update release communication and package metadata
gimlichael Jun 5, 2026
d5e62be
🙈 add generated assets to gitignore
gimlichael Jun 5, 2026
28acb90
👷 add support for macOS tests in CI pipeline configuration
gimlichael Jun 5, 2026
4580460
✨ support configurable application stop behavior in host factory
aicia-bot Jun 5, 2026
648c26a
🔧 disable analyzers and adjust warning levels in project files
gimlichael Jun 5, 2026
076503f
♻️ Remove LastValue support from bootstrapper markers
aicia-bot Jun 5, 2026
c75ac31
✅ Add async disposal test for ApplicationTestFactory
aicia-bot Jun 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,25 @@ The `Codebelt.Extensions.Xunit.Hosting.AspNetCore` namespace contains types that

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

Complements: [Microsoft.AspNetCore.TestHost namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.testhost) 🔗

### Extension Methods

|Type|Ext|Methods|
|--:|:-:|---|
Complements: [Microsoft.AspNetCore.TestHost namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.testhost) 🔗

### Fixture Naming Convention

ASP.NET Core host fixtures follow the same lifecycle naming convention as the hosting package:

|Prefix|Convention|
|---|---|
|`Managed`|The fixture owns host creation, configuration, startup and disposal using the default host runner.|
|`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.|

Application-entry-point fixtures use the `BlockingManaged` prefix by default. ASP.NET Core application tests expose a `TestServer`, and callers should receive a started server after fixture initialization. Use `BlockingManagedWebApplicationFixture<TEntryPoint>` when testing an existing ASP.NET Core application entry point with `TestServer`.

`BlockingManagedWebHostFixture` remains the opt-in blocking variant for the lower-level web host fixture family. The application-entry-point fixture is named `BlockingManagedWebApplicationFixture<TEntryPoint>` directly because this API is blocking by convention from its first release.

### Extension Methods

|Type|Ext|Methods|
|--:|:-:|---|
|HttpClient|⬇️|`ToHttpResponseMessageAsync`|
|IServiceCollection|⬇️|`AddFakeHttpContextAccessor`|
24 changes: 18 additions & 6 deletions .docfx/api/namespaces/Codebelt.Extensions.Xunit.Hosting.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,24 @@ The `Codebelt.Extensions.Xunit.Hosting` namespace contains types that provides a

[!INCLUDE [availability-default](../../includes/availability-default.md)]

Complements: [xUnit: Shared Context between Tests](https://xunit.net/docs/shared-context) 🔗

### Extension Methods

|Type|Ext|Methods|
|--:|:-:|---|
Complements: [xUnit: Shared Context between Tests](https://xunit.net/docs/shared-context) 🔗

### Fixture Naming Convention

Host fixtures follow a lifecycle naming convention:

|Prefix|Convention|
|---|---|
|`Managed`|The fixture owns host creation, configuration, startup and disposal using the default host runner.|
|`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.|

Application-entry-point fixtures use the `BlockingManaged` prefix by default. Existing application entry points are discovered and built from their `Program` assembly, so tests should receive a ready host after fixture initialization. Use `BlockingManagedApplicationFixture<TEntryPoint>` when testing console, worker or generic host applications from an existing entry point.

### Extension Methods

|Type|Ext|Methods|
|--:|:-:|---|
|ILogger{T}|⬇️|`GetTestStore`|
|IServiceCollection|⬇️|`AddXunitTestOutputHelperAccessor`|
|IServiceProvider|⬇️|`GetRequiredScopedService`|
87 changes: 80 additions & 7 deletions .github/workflows/ci-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ on:
options:
- Debug
- Release
run_mac_tests:
type: boolean
description: Run the macOS test matrix despite the additional cost and runtime.
default: false

permissions:
contents: read
Expand All @@ -21,6 +25,7 @@ jobs:
name: initialize
runs-on: ubuntu-24.04
outputs:
run-mac-tests: ${{ steps.vars.outputs.run-mac-tests }}
run-privileged-jobs: ${{ steps.vars.outputs.run-privileged-jobs }}
strong-name-key-filename: ${{ steps.vars.outputs.strong-name-key-filename }}
build-switches: ${{ steps.vars.outputs.build-switches }}
Expand All @@ -29,6 +34,12 @@ jobs:
name: calculate workflow variables
shell: bash
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.run_mac_tests }}" == "true" ]]; then
echo "run-mac-tests=true" >> "$GITHUB_OUTPUT"
else
echo "run-mac-tests=false" >> "$GITHUB_OUTPUT"
fi

if [[ "${{ github.event_name }}" == "pull_request" && "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]]; then
echo "run-privileged-jobs=false" >> "$GITHUB_OUTPUT"
echo "strong-name-key-filename=" >> "$GITHUB_OUTPUT"
Expand Down Expand Up @@ -101,10 +112,72 @@ jobs:
build: true # we need to build for .net48 tests
download-pattern: build-${{ matrix.configuration }}-${{ matrix.arch }}

test_mac:
if: ${{ needs.init.outputs.run-mac-tests == 'true' }}
name: call-test-mac
needs: [init, build]
strategy:
fail-fast: false
matrix:
arch: [X64, ARM64]
configuration: [Debug, Release]
uses: codebeltnet/jobs-dotnet-test/.github/workflows/default.yml@v3
with:
runs-on: ${{ matrix.arch == 'ARM64' && 'macos-26' || 'macos-26-intel' }}
configuration: ${{ matrix.configuration }}
build-switches: -p:SkipSignAssembly=true
restore: true
build: true # required for xunitv3
download-pattern: build-${{ matrix.configuration }}-${{ matrix.arch }}

test_qualitygate:
if: ${{ always() }}
name: test-qualitygate
needs: [init, test_linux, test_windows, test_mac]
runs-on: ubuntu-24.04
steps:
- name: Evaluate test results
shell: bash
env:
RUN_MAC_TESTS: ${{ needs.init.outputs.run-mac-tests }}
TEST_LINUX_RESULT: ${{ needs.test_linux.result }}
TEST_WINDOWS_RESULT: ${{ needs.test_windows.result }}
TEST_MAC_RESULT: ${{ needs.test_mac.result }}
run: |
require_success() {
local job_name="$1"
local job_result="$2"

if [[ "$job_result" != "success" ]]; then
echo "::error::$job_name finished with '$job_result'."
exit 1
fi
}

require_success_or_skip() {
local job_name="$1"
local job_enabled="$2"
local job_result="$3"

if [[ "$job_enabled" == "true" ]]; then
require_success "$job_name" "$job_result"
return
fi

if [[ "$job_result" != "success" && "$job_result" != "skipped" ]]; then
echo "::error::$job_name finished with '$job_result' while disabled."
exit 1
fi
}

require_success "test_linux" "$TEST_LINUX_RESULT"
require_success "test_windows" "$TEST_WINDOWS_RESULT"
require_success_or_skip "test_mac" "$RUN_MAC_TESTS" "$TEST_MAC_RESULT"

sonarcloud:
if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }}
if: ${{always() && needs.init.outputs.run-privileged-jobs == 'true' && needs.build.result == 'success' && needs.test_qualitygate.result == 'success'}}
name: call-sonarcloud
needs: [init, build, test_linux, test_windows]
needs: [init, build, test_qualitygate]
uses: codebeltnet/jobs-sonarcloud/.github/workflows/default.yml@v3
with:
organization: geekle
Expand All @@ -113,26 +186,26 @@ jobs:
secrets: inherit

codecov:
if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }}
if: ${{always() && needs.init.outputs.run-privileged-jobs == 'true' && needs.build.result == 'success' && needs.test_qualitygate.result == 'success'}}
name: call-codecov
needs: [init, build, test_linux, test_windows]
needs: [init, build, test_qualitygate]
uses: codebeltnet/jobs-codecov/.github/workflows/default.yml@v1
with:
repository: codebeltnet/xunit
secrets: inherit

codeql:
if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }}
if: ${{always() && needs.init.outputs.run-privileged-jobs == 'true' && needs.build.result == 'success' && needs.test_qualitygate.result == 'success'}}
name: call-codeql
needs: [init, build, test_linux, test_windows]
needs: [init, build, test_qualitygate]
uses: codebeltnet/jobs-codeql/.github/workflows/default.yml@v3
permissions:
security-events: write

deploy:
if: github.event_name != 'pull_request'
name: call-nuget
needs: [build, pack, test_linux, test_windows, sonarcloud, codecov, codeql]
needs: [build, pack, test_qualitygate, sonarcloud, codecov, codeql]
uses: codebeltnet/jobs-nuget-push/.github/workflows/default.yml@v3
with:
version: ${{ needs.build.outputs.version }}
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -373,4 +373,6 @@ FodyWeavers.xsd
*.code-workspace

# Strong-Name Key
*.snk
*.snk

.bot/
6 changes: 6 additions & 0 deletions .nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Version: 11.1.0
Availability: .NET 10 and .NET 9

# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)

Version: 11.0.10
Availability: .NET 10 and .NET 9

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
Version: 11.0.10
Version: 11.1.0
Availability: .NET 10 and .NET 9

# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)

Version: 11.0.9
# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)

# New Features
- ADDED WebApplicationTestFactory class in the Codebelt.Extensions.Xunit.Hosting.AspNetCore namespace for simplified static creation of ASP.NET Core application tests from a TEntryPoint with BlockingManagedWebApplicationFixture{TEntryPoint} as the default fixture
- ADDED WebApplicationTest{TEntryPoint,T}, IWebApplicationFixture{TEntryPoint}, BlockingManagedWebApplicationFixture{TEntryPoint} and WebApplicationFixtureExtensions in the Codebelt.Extensions.Xunit.Hosting.AspNetCore namespace to support Program.cs based ASP.NET Core tests with TestServer

Version: 11.0.10
Availability: .NET 10 and .NET 9

# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)

Version: 11.0.9
Availability: .NET 10 and .NET 9

# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)

Expand Down
21 changes: 16 additions & 5 deletions .nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
Version: 11.0.10
Version: 11.1.0
Availability: .NET 10, .NET 9 and .NET Standard 2.0

# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)

Version: 11.0.9
# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)

# New Features
- ADDED ApplicationHostFactory class in the Codebelt.Extensions.Xunit.Hosting namespace for creating started IHost instances from an application entry point assembly
- ADDED ApplicationTestFactory class in the Codebelt.Extensions.Xunit.Hosting namespace for simplified static creation of application tests from a TEntryPoint with BlockingManagedApplicationFixture{TEntryPoint} as the default fixture
- ADDED ApplicationTest{TEntryPoint,T}, IApplicationFixture{TEntryPoint}, BlockingManagedApplicationFixture{TEntryPoint} and ApplicationFixtureExtensions in the Codebelt.Extensions.Xunit.Hosting namespace to support Program.cs based host tests for console, worker and generic host applications

Version: 11.0.10
Availability: .NET 10, .NET 9 and .NET Standard 2.0

# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)

Version: 11.0.9
Availability: .NET 10, .NET 9 and .NET Standard 2.0

# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)

Expand Down
Loading
Loading