Skip to content

v6.0.0: Modernize Azure Functions and Aspire testing - #107

Open
chullybun wants to merge 11 commits into
mainfrom
v6.0.0
Open

chullybun wants to merge 11 commits into
mainfrom
v6.0.0

Conversation

@chullybun

@chullybun chullybun commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Overview

This is the UnitTestEx v6.0.0 major release. It moves the supported baseline to .NET 8, 9 and 10 and aligns Azure Functions testing with the v4 isolated worker model, removing the legacy in-process path and out-of-support .NET targets. The goal is to keep UnitTestEx aligned with the supported Azure Functions/.NET ecosystem while preserving its low-friction testing model, including real application startup, trigger and middleware execution, assertions, and captured logging.

v6.0.0 changes

  • Breaking: Target frameworks are now net8.0, net9.0 and net10.0 only; net6.0 and net7.0 (both out of support) have been removed.
  • Breaking: UnitTestEx.Azure.Functions supports the Azure Functions v4 isolated worker model only; in-process (WebJobs) support has been removed, including the FunctionsStartup entry point and CreateWebJobsServiceBus*MessageActions. See Migrating from v5 to v6.
  • Breaking: UnitTestEx.Azure.ServiceBus has been removed; its CreateServiceBusMessage* helpers now live in UnitTestEx.Azure.Functions (same UnitTestEx namespace).
  • Enhancement: FunctionTester runs the function app's real Program.cs (top-level statements supported; no test-specific structure required), capturing the host at Build() without starting the worker; test configuration and service overrides are applied. TEntryPoint is any type within the function app assembly.
  • Enhancement: HttpTrigger<T> supports both ASP.NET Core integration (HttpRequest → IActionResult/IResult) and built-in (HttpRequestData → HttpResponseData) HTTP models, asserted consistently via HttpResponseMessageAssertor; method and route are validated against the worker HttpTriggerAttribute.
  • Enhancement: Trigger<T> enables any other trigger type to be tested, with FunctionOutputAssertor for multi-output bindings.
  • Enhancement: Added Event Grid builders: CreateEventGridEvent* and CreateCloudEvent*.
  • Enhancement: Added Event Hubs EventData builders for values, JSON, resources and raw bodies, with broker metadata support.
  • Enhancement: Added Aspire integration coverage and documentation for a Service Bus-triggered Functions app using Microsoft's Service Bus emulator.
  • Enhancement: FunctionTester now runs the function app's worker middleware pipeline (including the ASP.NET Core integration) around the invoked method, so middleware logging, short-circuiting and exception mapping can be asserted. Use UseWorkerMiddleware(false) to invoke the method directly.
  • Breaking: Added IHttpMockRequest.WithNoBody() (implemented by MockHttpClientRequest and AspireHttpMockRequest), which matches a request with no body: absent or zero-length. The two are indistinguishable on the wire, so both tiers treat them identically. As a result:
    • Tier 1's default (no body configured) now also matches zero-length content, where previously only Content == null matched.
    • The shared IHttpMockClient.WithRequestsFromResourceAsync loader now treats an omitted body as WithNoBody(), consistent with Tier 1's native loader. Previously it matched any body, so Aspire stubs that omit body no longer match requests that have one; use body: ^ for that. On Aspire, GET/HEAD (or an unspecified method) apply no body constraint, as WireMock.Net does not read those bodies by default.
  • Documentation: README restructured into a front door with a capability matrix linking to example tests; detailed documentation moved to docs/.

chullybun and others added 6 commits October 28, 2026 14:22
- Target net8.0/net9.0/net10.0 only; remove net6/net7 conditional code.
- Remove UnitTestEx.Azure.ServiceBus; move ServiceBus helpers into UnitTestEx.Azure.Functions (no reflection).
- FunctionTester builds the isolated worker host by executing the app's own entry point (top-level Program.cs as-is), capturing the host at Build() and never starting the worker.
- Relax FunctionTester TEntryPoint new() constraint; any app type can be the marker.
- Isolated sample uses template-style Program.cs and Worker 2.x; add isolated tests.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Remove in-process/WebJobs support, legacy FunctionsStartup fallback and WebJobs Service Bus assertors
- Add generic TriggerTester (instance and static methods) and FunctionOutputAssertor for multi-output functions
- Support HttpRequest/IActionResult/IResult and HttpRequestData/HttpResponseData with HttpResponseMessage assertion
- Migrate in-process test fixture to UnitTestEx.IsolatedFunction; update NUnit/xUnit/MSTest tests
- Update README for isolated-worker model

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add worker middleware testing, Event Grid helpers, HTTP no-body matching, and expand documentation and coverage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Expand isolated Functions trigger helpers, add Service Bus emulator integration coverage, update docs, and run CI tests sequentially across .NET 8/9/10.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 29, 2026 17:50
@chullybun chullybun changed the title Add Event Hubs and Service Bus testing v6.0.0: Modernize Azure Functions and Aspire testing Oct 29, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved critical defects allow tests to hang despite timeouts, lose middleware changes through duplicate argument evaluation, and prevent the Service Bus Functions host from starting on a clean checkout.

6 open issues
What changed in this PR

This PR expands Azure Functions and Aspire testing support, adds Event Hubs builders and Service Bus emulator coverage, and migrates to isolated-worker Functions on .NET 8–10.

Changes:

  • Add host capture, middleware-aware invocation, event builders, and HTTP/multi-output assertions.
  • Add Aspire emulator fixtures, shared lifecycle support, asynchronous polling, and consistent no-body HTTP mocking.
  • Migrate cross-framework tests, document v6 changes, and run CI test projects sequentially.

This pull request requires changes. Three critical and four moderate findings remain unresolved, covering invocation correctness, timeout enforcement, event metadata, optional query parameters, and integration-host startup.

File Description
tests/​UnitTestEx.Xunit.Test/​UnitTestEx.Xunit.Test.csproj Reference isolated-worker fixtures and HTTP compatibility helpers.
tests/​UnitTestEx.Xunit.Test/​ServiceBusFunctionTest.cs Migrate Service Bus tests to isolated workers.
tests/​UnitTestEx.Xunit.Test/​Resources/​HttpMockInterfaceTest-mock.unittestex.yaml Add an omitted-body stub.
tests/​UnitTestEx.Xunit.Test/​ProductFunctionTest.cs Migrate product function tests.
tests/​UnitTestEx.Xunit.Test/​PersonFunctionTest.cs Migrate person function tests and request construction.
tests/​UnitTestEx.Xunit.Test/​MockHttpClientTest.cs Import HTTP JSON extensions.
tests/​UnitTestEx.Xunit.Test/​HttpMockInterfaceTest.cs Test absent and empty request-body matching.
tests/​UnitTestEx.NUnit.Test/​UnitTestEx.NUnit.Test.csproj Remove legacy fixture references and add compatibility helpers.
tests/​UnitTestEx.NUnit.Test/​StorageTriggerTest.cs Add blob and queue invocation tests.
tests/​UnitTestEx.NUnit.Test/​ServiceBusFunctionTest.cs Migrate invocation and settlement assertions.
tests/​UnitTestEx.NUnit.Test/​ProductFunctionTest.cs Migrate HTTP and timer tests.
tests/​UnitTestEx.NUnit.Test/​Other/​OneOffTestSetUpTest.cs Use an isolated-worker fixture.
tests/​UnitTestEx.NUnit.Test/​Other/​ExpectationsTest.cs Document the synchronous assertion helper.
tests/​UnitTestEx.NUnit.Test/​Other/​EventuallyAsyncTest.cs Test polling, timeout, and cancellation behavior.
tests/​UnitTestEx.NUnit.Test/​Other/​DocumentationLinksTest.cs Validate relative documentation links.
tests/​UnitTestEx.NUnit.Test/​Other/​DependencyInjectionTest.cs Cover service replacement, mocking, and scoped resolution.
tests/​UnitTestEx.NUnit.Test/​MockHttpClientTest.cs Import HTTP JSON extensions.
tests/​UnitTestEx.NUnit.Test/​EventHubsTest.cs Cover Event Hubs builders and trigger invocation.
tests/​UnitTestEx.NUnit.Test/​EventGridExtensionMethodsTest.cs Cover Event Grid and CloudEvent builders.
tests/​UnitTestEx.MSTest.Test/​UnitTestEx.MSTest.Test.csproj Reference isolated-worker fixtures and compatibility helpers.
tests/​UnitTestEx.MSTest.Test/​ServiceBusFunctionTest.cs Migrate Service Bus tests.
tests/​UnitTestEx.MSTest.Test/​ProductFunctionTest.cs Migrate product function tests.
tests/​UnitTestEx.MSTest.Test/​PersonFunctionTest.cs Migrate person function tests.
tests/​UnitTestEx.MSTest.Test/​Other/​JsonElementComparerTest.cs Make expected difference separators explicit.
tests/​UnitTestEx.MSTest.Test/​MockHttpClientTest.cs Import HTTP JSON extensions.
tests/​UnitTestEx.IsolatedFunction/​UnitTestEx.IsolatedFunction.csproj Target .NET 8–10 and update worker extensions.
tests/​UnitTestEx.IsolatedFunction/​TestMiddleware.cs Add logging, denial, and exception-handling fixtures.
tests/​UnitTestEx.IsolatedFunction/​StorageTriggerFunctions.cs Add blob and queue function fixtures.
tests/​UnitTestEx.IsolatedFunction/​Startup.cs Remove the custom startup bridge.
tests/​UnitTestEx.IsolatedFunction/​ServiceBusFunction.cs Expand isolated-worker Service Bus scenarios.
tests/​UnitTestEx.IsolatedFunction/​Program.cs Configure services and middleware through normal startup.
tests/​UnitTestEx.IsolatedFunction/​ProductFunction.cs Add isolated-worker HTTP and timer fixtures.
tests/​UnitTestEx.IsolatedFunction/​PersonFunction.cs Add isolated-worker person endpoints.
tests/​UnitTestEx.IsolatedFunction/​HttpVariantFunctions.cs Add HTTP response-model and multi-output fixtures.
tests/​UnitTestEx.IsolatedFunction/​EventHubsFunctions.cs Add single-event, batch, and failure fixtures.
tests/​UnitTestEx.Function/​UnitTestEx.Function.csproj Remove the in-process sample project.
tests/​UnitTestEx.Function/​Startup.cs Remove WebJobs startup configuration.
tests/​UnitTestEx.Function/​ServiceBusFunction.cs Remove in-process Service Bus fixtures.
tests/​UnitTestEx.Function/​Properties/​serviceDependencies.local.json Remove legacy local dependency metadata.
tests/​UnitTestEx.Function/​Properties/​serviceDependencies.json Remove legacy dependency metadata.
tests/​UnitTestEx.Function/​ProductFunction.cs Remove in-process product fixtures.
tests/​UnitTestEx.Function/​PersonFunction.cs Remove in-process person fixtures.
tests/​UnitTestEx.Function/​host.json Remove the legacy sample’s host configuration.
tests/​UnitTestEx.Function/​.gitignore Remove the legacy project’s ignore rules.
tests/​UnitTestEx.Aspire.Xunit.Test/​Resources/​AspireTesterTest-mock.unittestex.yaml Add an omitted-body Aspire stub.
tests/​UnitTestEx.Aspire.Xunit.Test/​AspireTesterTest.cs Test Aspire no-body matching.
tests/​UnitTestEx.Aspire.ServiceBus.Function/​UnitTestEx.Aspire.ServiceBus.Function.csproj Add a dedicated Service Bus function project. critical — 3 votes, line 14: Add a minimal version-2 host.json and copy it to output; Core Tools otherwise cannot locate the app root.
tests/​UnitTestEx.Aspire.ServiceBus.Function/​ServiceBusEchoFunction.cs Echo triggered messages to an output queue.
tests/​UnitTestEx.Aspire.ServiceBus.Function/​Program.cs Add standard worker startup.
tests/​UnitTestEx.Aspire.ServiceBus.AppHost/​UnitTestEx.Aspire.ServiceBus.AppHost.csproj Add the Service Bus integration AppHost.
tests/​UnitTestEx.Aspire.ServiceBus.AppHost/​ServiceBus/​Config.json Define emulator input and output queues.
tests/​UnitTestEx.Aspire.ServiceBus.AppHost/​AppHost.cs Orchestrate SQL, Service Bus, and Core Tools. moderate — 1 vote, line 36: Manage Azurite with a startup dependency or provide working storage; UseDevelopmentStorage=true currently relies on an external local process.
tests/​UnitTestEx.Aspire.NUnit.Test/​UnitTestEx.Aspire.NUnit.Test.csproj Reference storage clients and integration AppHosts.
tests/​UnitTestEx.Aspire.NUnit.Test/​Functions/​ServiceBusEmulatorTest.cs Exercise broker-triggered processing and output.
tests/​UnitTestEx.Aspire.NUnit.Test/​Functions/​AzuriteBlobTriggerTest.cs Exercise blob webhook processing and output.
tests/​UnitTestEx.Aspire.NUnit.Test/​AspireTesterTest.cs Share an AppHost and test lifecycle hooks.
tests/​UnitTestEx.Aspire.Functions.AppHost/​UnitTestEx.Aspire.Functions.AppHost.csproj Add the storage integration AppHost.
tests/​UnitTestEx.Aspire.Functions.AppHost/​AppHost.cs Launch Azurite and the Functions host. moderate — 2 votes, line 23: Restrict the fixture to the blob function and update expectations, or provision Service Bus/Event Hubs connections to avoid unrelated trigger errors.
tests/​UnitTestEx.Api/​Controllers/​PersonController.cs Update query-parameter nullability. moderate — 3 votes, line 46: Mark both name parameters nullable; [ApiController] otherwise returns HTTP 400 when they are omitted, breaking GetByArgs_Test2.
src/​UnitTestEx/​UnitTestEx.csproj Drop older frameworks and expose internals to Functions.
src/​UnitTestEx/​Schema/​mock.unittestex.json Describe omitted-body matching semantics.
src/​UnitTestEx/​Resource.cs Document YAML scalar resolution.
src/​UnitTestEx/​ObjectComparer.cs Remove legacy framework branches.
src/​UnitTestEx/​Mocking/​MockHttpClientResponse.cs Simplify JSON syntax annotations.
src/​UnitTestEx/​Mocking/​MockHttpClientRequest.cs Add explicit no-body and empty-content matching.
src/​UnitTestEx/​Mocking/​MockHttpClient.cs Simplify URI syntax annotations.
src/​UnitTestEx/​Mocking/​IHttpMockRequest.cs Expose the shared no-body contract.
src/​UnitTestEx/​Mocking/​HttpMockResourceConfig.cs Apply no-body semantics to omitted resource bodies.
src/​UnitTestEx/​Logging/​LoggerBase.cs Remove obsolete scope-signature branching.
src/​UnitTestEx/​Json/​JsonElementComparer.cs Simplify JSON syntax annotations.
src/​UnitTestEx/​Hosting/​HostTesterBase.cs Add synchronous/static execution and pipeline interception. critical — 3 votes, line 190: Invoke with already evaluated arguments; reevaluating the expression gives middleware and the function different request/context instances, losing middleware changes.
src/​UnitTestEx/​Hosting/​EntryPoint.cs Make modern host configuration unconditional.
src/​UnitTestEx/​Generic/​GenericTesterCore.cs Remove the legacy host-building path.
src/​UnitTestEx/​Expectations/​ExpectationsExtensions.cs Simplify JSON expectation declarations.
src/​UnitTestEx/​Assertors/​ValueAssertor.cs Remove legacy JSON and HTTP-result branches.
src/​UnitTestEx/​Assertors/​HttpResultAssertor.cs Make HTTP-result assertions unconditional.
src/​UnitTestEx/​Assertors/​HttpResponseMessageAssertorBaseT.cs Simplify JSON assertion declarations.
src/​UnitTestEx/​Assertors/​ActionResultAssertor.cs Simplify JSON assertion declarations.
src/​UnitTestEx/​AspNetCore/​HttpTesterT.cs Remove legacy URI annotation branches.
src/​UnitTestEx/​AspNetCore/​HttpTesterBase.cs Simplify HTTP request method declarations.
src/​UnitTestEx/​AspNetCore/​HttpTester.cs Simplify public HTTP tester declarations.
src/​UnitTestEx/​Abstractions/​TesterBaseCore.cs Add asynchronous polling. critical — 3 votes, line 177: Bound the returned-task wait with operationToken, retaining timeout-to-TimeoutException conversion; token-ignoring actions can otherwise hang despite timeout or caller cancellation.
src/​UnitTestEx.Xunit/​UnitTestEx.Xunit.csproj Target .NET 8–10 only.
src/​UnitTestEx.NUnit/​UnitTestEx.NUnit.csproj Target .NET 8–10 only.
src/​UnitTestEx.MSTest/​UnitTestEx.MSTest.csproj Target .NET 8–10 only.
src/​UnitTestEx.Azure.ServiceBus/​UnitTestEx.Azure.ServiceBus.csproj Remove the standalone Service Bus package project.
src/​UnitTestEx.Azure.Functions/​UnitTestEx.Azure.Functions.csproj Drop WebJobs dependencies and add event SDKs.
src/​UnitTestEx.Azure.Functions/​ServiceBusExtensionMethods.cs Provide relocated Service Bus message builders.
src/​UnitTestEx.Azure.Functions/​FunctionTester.cs Accept any application-assembly marker type.
src/​UnitTestEx.Azure.Functions/​EventHubsExtensionMethods.cs Add received Event Hubs event builders.
src/​UnitTestEx.Azure.Functions/​EventGridExtensionMethods.cs Add Event Grid, CloudEvent, and blob-event builders.
src/​UnitTestEx.Azure.Functions/​Azure/​Functions/​WorkerServiceBusMessageActionsAssertor.cs Correct worker-specific documentation references.
src/​UnitTestEx.Azure.Functions/​Azure/​Functions/​TestHttpResponseData.cs Add worker response and cookie implementations.
src/​UnitTestEx.Azure.Functions/​Azure/​Functions/​TestHttpRequestData.cs Wrap ASP.NET Core requests for worker tests.
src/​UnitTestEx.Azure.Functions/​Azure/​Functions/​TestFunctionContext.cs Add a configurable worker invocation context.
src/​UnitTestEx.Azure.Functions/​Azure/​Functions/​ServiceBusMessageActionStatus.cs Reference worker settlement APIs in documentation.
src/​UnitTestEx.Azure.Functions/​Azure/​Functions/​HttpResponseDataAssertor.cs Convert worker responses for HTTP assertions.
src/​UnitTestEx.Azure.Functions/​Azure/​Functions/​FunctionTesterT.cs Remove the parameterless-constructor requirement.
src/​UnitTestEx.Azure.Functions/​Azure/​Functions/​FunctionOutputAssertor.cs Add multi-output property and HTTP assertions.
src/​UnitTestEx.Azure.Functions/​Azure/​Functions/​FunctionHostFactory.cs Capture application hosts without starting workers.
src/​UnitTestEx.Aspire/​WithAspireTester.cs Add shared-fixture lifecycle and disposal support.
src/​UnitTestEx.Aspire/​UnitTestEx.Aspire.csproj Add Event Grid and MessagePack dependencies.
src/​UnitTestEx.Aspire/​Aspire/​HttpMock/​AspireHttpMockRequest.cs Implement Aspire no-body matching.
src/​UnitTestEx.Aspire/​Aspire/​FunctionsWebhookClient.cs Post Event Grid notifications to runtime webhooks. moderate — 2 votes, line 100: Preserve the supplied Topic; use the placeholder only when absent so topic-dependent functions receive faithful metadata.
docs/​test-setup-and-extensibility.md Explain setup, framework support, and extension hooks.
docs/​migration-v6.md Document breaking changes and migration steps.
docs/​generic-testing.md Explain generic and scoped testing.
docs/​dependency-injection-and-configuration.md Explain overrides, configuration, and host lifetime.
docs/​assertions-and-expectations.md Explain assertions, comparisons, and logging.
docs/​api-testing.md Explain controller and HTTP testing.
CHANGELOG.md Record v6 changes and update documentation links.
.github/​workflows/​ci.yml Install Core Tools and test .NET 8–10 sequentially.

Review effort: Balanced

chullybun and others added 5 commits October 29, 2026 10:59
Document Event Hubs and Service Bus additions in the v6.0.0 changelog.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Eric Sibly <eric.sibly@avanade.com>
Bound eventual-operation waits, reuse evaluated invocation arguments, preserve Event Grid topics, and make the blob and Service Bus emulator fixtures self-contained. Add regression coverage and update Aspire documentation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Eric Sibly <eric.sibly@avanade.com>
Remove the redundant target framework override from the single-target Functions project reference so MSBuild reuses the solution build instance instead of concurrently writing the same outputs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Eric Sibly <eric.sibly@avanade.com>
- Set package version to 6.0.0 and update NuGet publishing.
- Improve Aspire and Azure Functions host lifecycle, scope cleanup, and error handling.
- Define HTTP mock body matching for empty and non-empty requests.
- Make `ValueAssertor.AssertJson` compare JSON structurally.
- Update documentation and add regression tests.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants