Don't use Moq, use Simple or InMemory, or a local Fake#328
Merged
Conversation
Migrate four legacy test files off Moq and inline nested test doubles onto the Simple*/InMemory* doubles (ADR 0009) plus new recording test doubles. Structural (tidy-first), test-only change. Includes spec 007-use_simple_not_mocks: approved requirements, requirements/design adversarial reviews, and ADR 0013 (Proposed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Flip ADR 0013 status Proposed -> Accepted and record the .design-approved marker for spec 007-use_simple_not_mocks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the approved tasks.md (Tasks 0-11) for spec 007 legacy-test migration, the round-2 adversarial review (PASS), and the tasks-approval marker. Amend ADR 0013 with a 2026-06-05 addendum extending Decision 4 to a recording decorator-factory double (RecordingDecoratorFactory), so FallbackPolicyTests' decorator Release assertions are preserved as state rather than dropped (NFR1). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds README.md to Exported/ documenting that this directory holds the public test doubles discovered by assembly/handler scanning, distinct from TestDoubles/ (internal doubles used directly by tests). Records the green-suite baseline (Task 0) and ticks Tasks 0-1. Satisfies FR9, AC10. Structural, docs-only; no .cs change in Exported/. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…306) Moves TestQuery (+ Result), TestQueryHandlerWithCatchAllFallback, TestQueryHandlerWithFormatExceptionFallback, and TestQueryHandlerWithoutFormatExceptionFallback verbatim into TestDoubles/ (one type per file). FallbackPolicyTests now references them via a using; the Moq factory/registry usage is unchanged (swapped in Task 8). No nested double class declarations remain in the file. Satisfies FR3 (extraction half), FR5, AC6, AC7. Structural; suite green at baseline. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tDoubles (#306) Moves the exception-scenario queries/handlers (each Result with its owning query), TestExceptionDecorator<,>, and DecoratorExceptionAttribute verbatim into TestDoubles/. Private nested types promoted to internal (attribute stays public, as before). The test references them via a using; Moq factory/registry usage unchanged (swapped in Task 9). Satisfies FR4 (extraction half), FR5, AC6, AC7. Structural; suite green at baseline. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds generic recording query-handler doubles deriving from QueryHandler<,>/QueryHandlerAsync<,>: Execute/ExecuteAsync run a supplied delegate (which may throw) and record ExecuteCount/LastQuery; Fallback/FallbackAsync record FallbackCount then defer to base. The CancellationToken is threaded to the delegate but not recorded (behaviour-equivalent, FR10). Not yet referenced by any test. Satisfies FR10 (handler-recording double), groundwork for FR1/FR2. Structural; suite green at baseline; no src change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…#306) Adds RecordingHandlerFactory and RecordingDecoratorFactory (delegate-based Create like the Simple* factories, plus Release recording via ReleaseCount/Released) so the legacy Release Verify assertions migrate to state. Adds distinct-named QueryProcessor doubles — ProcessorQuery (Guid), ProcessorIntQuery (int), and ProcessorQueryHandler[Async] (write bag + return Id) — copied/renamed from the Exported analogues so the two roles stay separated (FR6, AC4, AC7). Not yet referenced by any test. Satisfies FR10 (recording factories), FR6. Structural; suite green; no src change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
) Replaces Mock<IQueryHandlerFactory> with RecordingHandlerFactory (fed by a per-test handler dictionary), the decorator mock with SimpleHandlerDecoratorFactory, and the registry mock with InMemoryDecoratorRegistry. Interaction Verify assertions become result-first / state reads: result.ShouldBe(id) proves the matching handler ran with the right query; ExecuteCount/FallbackCount cover the negatives; ReleaseCount replaces Release Verify. No Moq tokens remain; no Exported types referenced; [Fact] count unchanged (3). Satisfies FR1, FR7, FR10, AC2-AC5. Behaviour-preserving; suite green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…es (#306) Replaces the mocks with RecordingQueryHandlerAsync doubles, a shared SimpleHandlerDecoratorFactory + InMemoryDecoratorRegistry across both slots, and — critically — TWO separate RecordingHandlerFactory instances for the sync and async slots. The async pipeline creates via the async slot but releases via the sync slot, so the async factory's ReleaseCount(handler) is 0: the Times.Never asymmetry vs the sync file's Times.Once is preserved (NFR1), not tidied to match. Result-first assertions; CancellationToken not recorded. No Moq tokens; [Fact] count unchanged (3). Satisfies FR2, FR7, FR10, AC2-AC5. Behaviour-preserving; suite green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Swaps the factory/registry mocks for RecordingHandlerFactory, RecordingDecoratorFactory, and InMemoryDecoratorRegistry (fed by per-test handler/decorator dictionaries), consuming the doubles extracted in Task 2. The three handler Release Verify and three decorator Release Verify assertions become ReleaseCount(...).ShouldBe(1) state reads — preserved, not dropped (NFR1; ADR 0013 D4 addendum). Outcome/bag assertions unchanged. No Moq tokens; [Fact] count unchanged (3). Satisfies FR3 (factory-swap half), FR7, AC1, AC2. Behaviour-preserving; suite green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Swaps Mock<IQueryHandlerFactory> for RecordingHandlerFactory, Mock<IQueryHandlerDecoratorFactory> for plain SimpleHandlerDecoratorFactory (no decorator-Release assertion here), and the registry mock for InMemoryDecoratorRegistry with real Register(...) calls. The Release(It.IsAny<ExceptionQueryHandler>()) Times.Once check becomes Released.OfType<ExceptionQueryHandler>().Count().ShouldBe(1). Consumes the doubles extracted in Task 3; exception-message assertions unchanged. This was the last Moq consumer — none remain in the test project. [Fact] count unchanged (4). Satisfies FR4 (factory-swap half), FR7, AC1, AC2. Behaviour-preserving; suite green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deletes the Moq PackageReference from Paramore.Darker.Core.Tests and the Moq PackageVersion from Directory.Packages.props now that no test uses Moq. Build succeeds and the full filtered suite is green at the AC11 baseline. Satisfies FR8, AC12. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
All 14 acceptance criteria pass: no Moq anywhere (AC1/AC14), outcome assertions preserved (AC3), no Verify/Times/It and no Exported types in the QueryProcessor files (AC4/AC5), doubles extracted with no collisions (AC6/AC7), Exported/*.cs and src/ untouched (AC8/AC9), README present (AC10), [Fact] counts unchanged (AC13), suite green at baseline (AC11/AC12). Also rewords a doc comment so AC14's case-insensitive 'moq' sweep is clean. Satisfies AC1-AC14, Definition of Done. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Our agent can fix these. Install it.
No application code in the PR — skipped Code Health checks.
Quality Gate Profile: Clean Code Collective
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.
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.
We don't want to use a Moq framework, instead we provide lightweight alternatives to most dependencies or build a fake for a specific context.