Run a test's application on ASP.NET Core with [AspNetCoreHost] - #276
Merged
Merged
Conversation
The real pipeline is WebApplication's, and WebApplication builds its own container, so the attribute is also the runner's container builder: it copies the test's collection into a WebApplicationBuilder, builds, and hands the runner app.Services. The server, the mocks and the test's parameters resolve from one container. Not terminal: an unmatched path falls through to what the composition put behind UseHardened() and then to ASP.NET's own 404. IAspNetCoreTestComposition stands in for what Program.cs puts around Hardened. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
[AspNetCoreHost]on a[HardenedTest], a test class or the assembly runs the test's application inside the real ASP.NET Core pipeline, on Kestrel, on a loopback port the kernel picks: aWebApplicationbuilt the wayProgram.csbuilds one, over the test's own container. Everything the test holds follows it the way it does under[KestrelHost], and what this host adds is the pipeline around Hardened: anIAspNetCoreTestCompositionnamed in the attribute arranges the middleware the wayProgram.csdoes,app.UseHardened()alone by default, and an unmatched path falls through to what the composition put behind Hardened and then to ASP.NET's own 404, which is the behaviour this host exists to show.How
WebApplicationbuilds its own container, so the attribute is also the runner's container builder (IServiceProviderBuilderAttribute, which both DependencyModules runners honour): it copies every descriptor of the test's populated collection into aWebApplicationBuilder, builds, and returnsapp.Servicesas the test's provider. The server, the test's mocks and the test's parameters then resolve from one container, which is what keeps[Mock]true over this host. The ASP.NET environment name is the Hardened one in scope,testby default.Stopping: the host is a singleton in
app.Services, so the runner's disposal of the provider reaches it before Kestrel's registration; the shared transport is closed,app.StopAsyncruns withinSocketHost.StopBound, thenapp.DisposeAsync. Disposing the application disposes the provider that is already being disposed, which is safe because the container's dispose is guarded against re-entry; the port-closed test holds it.Held by
Hardened.Web.AspNetCore.Testing.Tests: the container the test resolves from is the application's own; a loopback port the kernel picked; the default composition serves through Hardened; an unmatched path is ASP.NET's own 404 with no body; a composition's middleware behind Hardened answers what Hardened passed on; the environment name is the Hardened one in scope; disposing the container closes the port; a composition that is not one is refused by name.AspNetCoreHostTestsin the web SUT's test project,[AspNetCoreHost]on the class: the request through the ASP.NET pipeline, a[Mock]behind a route, a Kiota client read byReturns<T>(),LastResponse, three parameters with three credentials, ASP.NET's own 404 for an unmatched path, the handler's exception not crossing the wire, and[PipelineHost]on one method getting it back.AspNetCoreHostUnderNUnitTestsin the NUnit project: the same on the other runner, whoseModuleTestCommandbuilds the container through the attribute the same way.Notes
test-hosts), which is stacked on Split the test runner out of Hardened.Shared.Testing #273.coverage-baseline.json, which the gate reads as unmeasured.IServiceProviderBuilderAttributeof its own conflicts with this attribute; the runner takes the narrowest. Nothing in this repository does.🤖 Generated with Claude Code