eshop-full — testing strategy

83 tests, four projects deep — and the fix decorators finally let get proven.

MSTest.Sdk on .NET's newer Microsoft.Testing.Platform (MTP) runner — already pinned in global.json from the original SDK research, not a new choice. Testing isn't a batched end-of-migration phase: every project gets its own test project in the same unit of work as its source files, before the source migration moves past it. See Event Flow for the Decorator split this testing approach depends on.

Coverage so far

ProjectSource files coveredTests
eShop.ServiceDefaults.UnitTests7 of 733
EventBusRabbitMQ.UnitTests6 of 6 applicable17
EventBus.UnitTests6 of 6 applicable16
IntegrationEventLogEF.UnitTests5 of 5 applicable17
Total83

"Applicable" excludes pure interfaces with zero behavior of their own (IEventBus, IEventBusBuilder) — stated explicitly per file, not silently assumed clean.

Patterns worth carrying forward

Decorator-enabled testing

Fake inner IEventBus, no broker needed

ResilientEventBusDecorator/TelemetryEventBusDecorator wrap any IEventBus — so their tests use a fake inner bus instead of a real RabbitMQ broker (which doesn't exist yet, no eShop.AppHost).

Proof: PublishAsync_retries_and_succeeds_after_a_transient_SocketException verifies the Polly fix end-to-end for the first time — closing a gap open since the fix landed.

InternalsVisibleTo

Test internal classes directly, don't reflect

OpenApiOptionsExtensions is internal end-to-end. Rather than reach for reflection (brittle, tests implementation detail) or skip coverage of logic that had already shipped one real bug, the members got widened to internal and <InternalsVisibleTo> added — no public API change.

NSubstitute

Already centrally pinned (upstream's own Ordering.UnitTests uses it) — first real use in this fork.

Mock the pipeline, not the class under test

HttpClientExtensions's bearer-token-injecting handler is a private nested class — only reachable through AddAuthToken's public surface plus a real IServiceCollection and a mocked IAuthenticationService standing in for the ASP.NET Core auth pipeline.

Real ActivityListener

Don't mock OpenTelemetry, listen to it for real

RabbitMQTelemetryTests.cs and TelemetryEventBusDecoratorTests.cs both use a real ActivityListener/ActivitySource to confirm the actual messaging semantic-convention tags land with the right values — not a mock standing in for what OpenTelemetry would do.

CI, verified not assumed

MTP is a genuinely different CLI surface from legacy VSTest-based dotnet test — its own --help states plainly it "doesn't support VSTest," so the familiar --collect:"XPlat Code Coverage"/--logger trx flags don't apply. Every flag below was confirmed against a real scratch MSTest.Sdk project before trusting it in CI.

Coverage + TRX

--coverage --coverage-output-format cobertura and --report-trx are both built into the MTP runner itself — no extra NuGet package needed for either.

PR-visible reporting

dorny/test-reporter@v3 publishes the .trx as a PR-visible check run; a real push confirmed "3 passed, 0 failed" rendering with each test named, end-to-end against actual GitHub Actions.

i

Honest gap, tracked not solved: wanted one combined HTML report across every test project — MTP's --report-html produces one file per project instead (confirmed via a real 2-project scratch solution). The actual fix, microsoft/testfx#10529, merged 2026-08-09 but hasn't shipped in a Microsoft.Testing.Extensions.HtmlReport NuGet release yet. Dependabot already tracks that package individually, so no new tooling is needed to know when it does.