FastMoq
Search Results for

    Provider Capabilities

    This page answers a practical question: what works with each FastMoq provider today, and what remains provider-specific or unsupported.

    Use it together with Provider Selection and Setup:

    • that page explains how provider registration and selection works
    • this page explains what each provider can actually do once selected

    Why this page exists

    FastMoq has two different layers of behavior:

    • provider-neutral APIs such as GetOrCreateMock(...), Verify(...), VerifyNoOtherCalls(...), and VerifyLogged(...)
    • count-oriented verification wrappers such as VerifyCalledOnce(...), VerifyNotCalled(...), VerifyLoggedOnce(...), and VerifyNotLogged(...) when the assertion is exactly once or never
    • broader count wrappers such as VerifyCalledExactly(...), VerifyCalledAtLeast(...), VerifyCalledAtMost(...), and the matching *AnyArgs(...) variants when the test wants provider-first counts without manual TimesSpec construction
    • method-group any-args verification through VerifyAnyArgs(...) when the test only cares that one non-overloaded method was called and every argument can stay wildcarded
    • a provider-neutral diagnostics snapshot through CreateDiagnosticsSnapshot() when the test needs to inspect tracked mocks, constructor selections, observed registrations, or captured log entries without dropping into provider-native debug surfaces
    • provider-specific capabilities and convenience APIs exposed by the selected provider

    The selected provider determines whether features such as protected-member access, automatic property backing, base-call behavior, and logger capture are available.

    Capability matrix

    These values reflect IMockingProviderCapabilities in the current v4 release line.

    Capability Moq NSubstitute Reflection
    SupportsCallBase Yes No No
    SupportsSetupAllProperties Yes No No
    SupportsProtectedMembers Yes No No
    SupportsInvocationTracking Yes Yes Yes
    SupportsLoggerCapture Yes Yes No

    What remains portable across providers

    These are the safest v4 APIs to document as provider-first or provider-neutral:

    • GetOrCreateMock<T>()
    • GetObject<T>()
    • Verify(...)
    • VerifyNoOtherCalls(...)
    • FastArg.Any(...), FastArg.Is(...), FastArg.IsNull(...), FastArg.IsNotNull(...), and FastArg.AnyExpression<T>() inside FastMoq-supported expression flows
    • Mocker.BuildExpression<T>() as a compatibility alias for expression-valued wildcard arguments
    • TimesSpec
    • VerifyLogged(...) when the selected provider supports logger capture
    • scenario-builder flows that rely on provider-neutral verification

    If you want migration guidance that will carry forward into v5 cleanly, start from those APIs first.

    Provider-first verify rule:

    • once the assertion is on Mocks.Verify<T>(...) or MockingProviderRegistry.Default.Verify(...), use FastArg.Any(...), FastArg.Is(...), FastArg.IsNull(...), FastArg.IsNotNull(...), or FastArg.AnyExpression<T>() inside that verification expression instead of It.IsAny(...) or It.Is(...)

    Example:

    Mocks.Verify<IOrderRepository>(
        x => x.Save(FastArg.Any<Order>()),
        TimesSpec.Once);
    

    Alternatives when a Moq feature is unavailable

    Some APIs are strongest in Moq today and do not have a fully equivalent provider-neutral shape.

    When that happens, use this rule:

    • prefer a provider-neutral FastMoq API when one exists
    • otherwise prefer a fake, stub, or real test double through AddType(...)
    • keep Moq only when the test fundamentally depends on behavior the other providers do not expose cleanly
    Moq-oriented feature Alternative outside Moq When Moq is still the right tool
    Setup(...) expression-based arrangement For exact-call fixed results, exact-call Task completions, exact-call callbacks, or exact-call exceptions, prefer AddMethodResult(...), AddMethodResultAsync(...), AddMethodCompletionAsync(...), AddMethodCallback(...), AddMethodCallbackAsync(...), AddMethodException(...), or AddMethodExceptionAsync(...). Otherwise use the selected provider's native arrangement style when it exists. For NSubstitute, translate Setup(...) into direct substitute calls such as substitute.Method(...).Returns(...), substitute.When(...).Do(...), Arg.Any<T>(), and Arg.Is<T>(...), or replace the collaborator with a fake/stub through AddType(...) when you want a provider-neutral path. For FastMoq-owned setup shortcuts on the Moq provider, prefer FastArg matchers such as FastArg.AnyExpression<T>() over adding new BuildExpression() usage. Keep FastMoq's verification APIs for the assert side when possible. When you are intentionally preserving existing Moq-shaped setup chains with minimal churn, or when the test depends on Moq-only expression setup behavior.
    VerifyLogger(...) Prefer VerifyLogged(...). For a first-party registration story, use AddCapturedLoggerFactory() to register callback-backed ILoggerFactory, ILogger, and ILogger<T> services directly on Mocker, or use CreateLoggerFactory() when you want to plug the same capture-backed factory into a typed IServiceProvider recipe. Use AddLoggerFactory(existingFactory) when the factory instance already exists outside FastMoq. When you are intentionally preserving older Moq-shaped logger assertions with minimal churn.
    Protected() for HttpMessageHandler Prefer WhenHttpRequest(...) or WhenHttpRequestJson(...) for HTTP behavior. When the test really depends on direct protected-member interception rather than request/response behavior.
    Protected() for arbitrary protected members Prefer testing through a public seam, extracted collaborator, or concrete fake. When the implementation cannot reasonably be reshaped and protected-member interception is the behavior under test.
    SetupSet(...) For simple interface-property cases, prefer AddPropertySetterCapture<TService, TValue>(...). For broader collaborator behavior, prefer a fake or stub registered with AddType(...) that captures assigned values, usually with PropertyValueCapture<TValue>, or verify the observable downstream behavior instead of the setter interception itself. When the setter interception is the important behavior and introducing a helper-backed replacement or fake would create more churn than value.
    SetupAllProperties() For simple interface-property state, prefer AddPropertyState<TService>(...). For broader collaborator behavior or class targets, prefer a concrete fake or lightweight test double with real property state via AddType(...). When you specifically want mocking-library-managed property backing without creating a custom fake.
    CallBase / partial mock behavior Prefer a real instance or AddType(...) factory for the concrete collaborator. When the test intentionally relies on partial mocking rather than a real implementation or fake.
    out / ref verification with It.Ref<T>.IsAny Prefer wrapping the dependency behind a simpler interface, or assert on the public result / side effect instead of the raw out / ref interaction. When the API shape is fixed and the out / ref interaction itself is important to the test.

    These alternatives are not identical replacements. They are the practical ways to stay productive when the provider-neutral or non-Moq providers do not expose the same mocking semantics.

    Moq provider

    Provider package / namespace:

    • package: FastMoq.Provider.Moq
    • namespace for tracked-mock extensions: FastMoq.Providers.MoqProvider

    Best fit:

    • lowest-churn migration from older Moq-shaped suites
    • tests that need protected-member access
    • tests that need automatic property backing or call-base semantics
    • tests that still rely on Moq-native verification or setup patterns

    Supported capability flags:

    • call base
    • setup all properties
    • protected members
    • invocation tracking
    • logger capture

    Provider-specific tracked-mock conveniences already exposed on IFastMock<T>:

    • AsMoq()
    • Setup(...)
    • SetupGet(...)
    • SetupSequence(...)
    • Protected()
    • VerifyLogger(...)
    • SetupLoggerCallback(...)

    Practical note:

    • if you need Moq-only APIs that are not wrapped as IFastMock<T> extensions, use GetOrCreateMock<T>().AsMoq() first
    • keep obsolete GetMock<T>() only as a compatibility path when preserving the old Moq shape is materially cheaper than rewriting the test

    Common Moq-only pockets:

    • SetupSet(...)
    • direct Mock<T> APIs not wrapped by FastMoq provider extensions
    • out / ref verification patterns using It.Ref<T>.IsAny

    Recommended style:

    using var providerScope = MockingProviderRegistry.Push("moq");
    var dependency = Mocks.GetOrCreateMock<IOrderGateway>();
    
    dependency.Setup(x => x.Publish("alpha"));
    dependency.Instance.Publish("alpha");
    
    Mocks.Verify<IOrderGateway>(x => x.Publish("alpha"), TimesSpec.Once);
    

    For the common once / never cases, the shared verification surface now has explicit wrappers:

    Mocks.VerifyCalledOnce<IOrderGateway>(x => x.Publish("alpha"));
    Mocks.VerifyNotCalled<IOrderGateway>(x => x.Publish("beta"));
    Mocks.VerifyCalledExactly<IOrderGateway>(x => x.Publish("alpha"), 2);
    Mocks.VerifyLoggedOnce(LogLevel.Information, "submitted alpha");
    Mocks.VerifyNotLogged(LogLevel.Error, "submission failed");
    Mocks.VerifyAnyArgs<IOrderGateway, Action<string>>(gateway => gateway.Publish, TimesSpec.Once);
    Mocks.VerifyCalledAtLeastAnyArgs<IOrderGateway, Action<string>>(gateway => gateway.Publish, 1);
    

    Detached handles can use the same style without routing through MockingProviderRegistry.Default manually:

    MockingProviderRegistry.VerifyCalledOnce(orderGateway, x => x.Publish("alpha"));
    MockingProviderRegistry.VerifyNotCalled(orderGateway, x => x.Publish("beta"));
    MockingProviderRegistry.VerifyAnyArgs<IOrderGateway, Action<string>>(orderGateway, gateway => gateway.Publish, TimesSpec.Once);
    MockingProviderRegistry.VerifyNoOtherCalls(orderGateway);
    

    For exact-call fixed results that do not need a broader provider-native setup chain, prefer the shared helper surface first:

    var gateway = Mocks.AddMethodResult<IOrderGateway, Order?>(
        x => x.Load("order-42"),
        expectedOrder);
    
    gateway.Load("order-42").Should().BeSameAs(expectedOrder);
    Mocks.Verify<IOrderGateway>(x => x.Load("order-42"), TimesSpec.Once);
    

    Use AddMethodResultAsync(...) for the same shape when the collaborator returns Task<T>, AddMethodCompletionAsync(...) when it returns Task, AddMethodCallback(...) / AddMethodCallbackAsync(...) when the exact-call behavior is a simple side effect, and AddMethodException(...) / AddMethodExceptionAsync(...) when the exact-call behavior is a fixed exception rather than a value.

    Shared setup helper boundary

    Use the shared setup helpers when the arranged behavior is narrow enough that FastMoq can own it directly.

    If the arranged behavior is... Prefer... Keyed-service note Fall back when...
    one exact-call fixed return, fixed Task<T> result, completed Task, callback, or exception on an interface collaborator AddMethodResult(...), AddMethodResultAsync(...), AddMethodCompletionAsync(...), AddMethodCallback(...), AddMethodCallbackAsync(...), AddMethodException(...), or AddMethodExceptionAsync(...) these helpers currently wrap the currently resolved service and do not expose keyed-specific overloads; when the collaborator role is keyed, keep the keyed separation first and then use a keyed tracked mock or keyed fake for that role the arrangement needs sequencing, conditional behavior, advanced callbacks, or a class target
    simple readable and writable property state on an interface collaborator AddPropertyState<TService>(...) AddPropertyState(...) currently wraps the currently resolved service and does not expose keyed-specific overloads; for keyed roles, prefer keyed mocks or keyed fixed instances first the target is a class, the state model is broader than simple property backing, or the keyed role needs its own explicit fake
    capturing assignments to one interface property AddPropertySetterCapture<TService, TValue>(...) AddPropertySetterCapture(...) currently wraps the currently resolved service and does not expose keyed-specific overloads; for keyed roles, prefer keyed mocks or keyed fixed instances first setter interception is not the real behavior under test, or the target is a class
    one fixed keyed dependency instance AddKeyedType(...) plus GetKeyedObject<T>(...) when needed keyed registrations are first-class here the dependency is still conceptually a mock that you want FastMoq to track

    Practical rule:

    • shared setup helpers are the first choice for unkeyed interface collaborators when the behavior is exact-call or simple property state
    • keyed DI contracts should preserve the key boundary first; if the helper shape still matters after that, use a keyed tracked mock or keyed fake instead of expecting the unkeyed helper overloads to retarget themselves
    • when the arrangement needs more than the table above, stay honest and use provider-native setup or an explicit fake/stub

    Shared verification boundary

    The shared verification surface is intentionally broader than the shared setup surface, but it still has explicit stop points.

    If the assertion is... Prefer... ScenarioBuilder note Stay provider-native when...
    exact-call verification with explicit argument intent Verify(...) with TimesSpec and FastArg markers where needed .Verify<T>(...) is the inline ScenarioBuilder path the test fundamentally depends on provider-only verification semantics
    once / never / exact count / at-least / at-most count VerifyCalledOnce(...), VerifyNotCalled(...), VerifyCalledExactly(...), VerifyCalledAtLeast(...), or VerifyCalledAtMost(...) ScenarioBuilder does not currently add separate count-wrapper methods; use .Verify<T>(..., TimesSpec...) inside the scenario or call the wrappers on Mocks / MockingProviderRegistry around execution the assertion is really about call order, sequences, or another provider-specific concept
    any-args verification for one non-overloaded member VerifyAnyArgs(...) and the matching *AnyArgs(...) count helpers use the normal .Verify<T>(...) path inside ScenarioBuilder when you need inline verification; use VerifyAnyArgs(...) around execution when the scenario only needs wildcard matching the member shape is provider-specific or the test needs a provider-native sequence / event assertion
    no-other-calls on a tracked or detached handle VerifyNoOtherCalls(...) .VerifyNoOtherCalls<T>() is supported inline on ScenarioBuilder the suite intentionally preserves a provider-native no-other-calls surface
    captured logger assertions VerifyLogged(...), VerifyLoggedOnce(...), and VerifyNotLogged(...) when the provider supports logger capture call the logger verification on Mocks around scenario execution; ScenarioBuilder does not add a separate logger-verification wrapper the selected provider does not support logger capture
    call order, sequences, events, protected members, or other provider-bound semantics the selected provider's native verification APIs do not expect ScenarioBuilder to flatten these into a shared abstraction the provider-specific feature is the thing under test

    When you need Moq-native behavior that is not exposed as a tracked shortcut, step through AsMoq():

    Mocks.GetOrCreateMock<IOrderGateway>()
        .AsMoq()
        .SetupSet(x => x.Mode = It.IsAny<string>());
    

    For simple SetupSet(...) cases on interface properties, the preferred first-party answer is AddPropertySetterCapture<TService, TValue>(...):

    var modeCapture = Mocks.AddPropertySetterCapture<IOrderGateway, string?>(x => x.Mode);
    CreateComponent();
    
    Component.Run();
    
    modeCapture.Value.Should().Be("fast");
    

    When the component under test comes from MockerTestBase<TComponent>, call CreateComponent() after adding the capture unless you registered it in the test base setup path before component creation.

    For simple SetupAllProperties() cases on interface collaborators, the preferred first-party answer is AddPropertyState<TService>(...):

    var channel = Mocks.AddPropertyState<IOrderSubmissionChannel>();
    CreateComponent();
    
    await Component.SubmitAsync("order-42", expedited: true, CancellationToken.None);
    
    channel.Mode.Should().Be("fast");
    

    That keeps the important part of the test explicit: the collaborator needs real property state, not Moq-specific property plumbing.

    AddPropertyState<TService>(...) keeps its original write-through behavior by default. If the test needs detached property state on the proxy registration without mutating the previously wrapped instance, use PropertyStateMode.ProxyOnly:

    var channel = Mocks.AddPropertyState<IOrderSubmissionChannel>(PropertyStateMode.ProxyOnly);
    CreateComponent();
    
    await Component.SubmitAsync("order-42", expedited: true, CancellationToken.None);
    
    channel.Mode.Should().Be("fast");
    

    If the collaborator needs more behavior than one captured property, or the target is not an interface, fall back to a fake plus PropertyValueCapture<TValue>:

    var modeCapture = new PropertyValueCapture<string?>();
    Mocks.AddType<IOrderGateway>(_ => new OrderGatewayStub(modeCapture));
    
    Component.Run();
    
    modeCapture.Value.Should().Be("fast");
    
    sealed class OrderGatewayStub(PropertyValueCapture<string?> capture) : IOrderGateway
    {
        public string? Mode
        {
            get => capture.Value;
            set => capture.Record(value);
        }
    }
    

    That combination keeps the test portable across providers, makes the arranged state explicit, and avoids tying the test to Moq-only setter interception when the important behavior is the assigned value.

    Repo-backed references:

    • FastMoq.Tests/MoqProviderExtensionTests.cs
    • FastMoq.Tests/ProviderTests.cs

    NSubstitute provider

    Provider package / namespace:

    • package: FastMoq.Provider.NSubstitute
    • namespace for tracked-mock extensions: FastMoq.Providers.NSubstituteProvider

    Best fit:

    • suites intentionally written against NSubstitute behavior
    • teams that want provider-neutral verification with NSubstitute-backed arrangement code

    Supported capability flags:

    • invocation tracking
    • logger capture

    Not supported by the provider capabilities:

    • call base
    • setup all properties
    • protected members

    Practical note:

    • prefer portable FastMoq verification APIs after arranging substitute behavior
    • if a test fundamentally depends on protected members or auto-backed property semantics, NSubstitute is not the right provider for that test shape today

    Recommended style:

    using var providerScope = MockingProviderRegistry.Push("nsubstitute");
    var dependency = Mocks.GetOrCreateMock<IOrderGateway>();
    
    dependency.AsNSubstitute().GetValue().Returns("configured");
    dependency.Instance.Publish("alpha");
    
    dependency.Received(1).Publish("alpha");
    Mocks.Verify<IOrderGateway>(x => x.Publish("alpha"), TimesSpec.Once);
    

    Quick Moq-to-NSubstitute translation rules:

    • Setup(x => x.Method()).Returns(value) becomes AsNSubstitute().Method().Returns(value)
    • Setup(x => x.Method(It.IsAny<T>())) becomes AsNSubstitute().Method(Arg.Any<T>())
    • Setup(x => x.Method(It.Is<T>(predicate))) becomes AsNSubstitute().Method(Arg.Is<T>(predicate))
    • Setup(x => x.VoidMethod()).Callback(...) becomes AsNSubstitute().When(x => x.VoidMethod()).Do(...)
    • SetupSequence(...) becomes Returns(value1, value2, ...)
    • SetupGet(...) becomes a direct property Returns(...)

    If a migrated test still needs Protected() or CallBase, that test should usually stay on Moq or move to a fake rather than trying to force an NSubstitute equivalent. For simple interface-property cases, prefer AddPropertySetterCapture<TService, TValue>(...) or AddPropertyState<TService>(...) before keeping SetupSet(...) or SetupAllProperties() purely for habit. PropertyValueCapture<TValue> remains the default FastMoq answer when the test only needs to observe property assignments rather than exercise Moq itself.

    Repo-backed references:

    • FastMoq.Tests/NSubstituteProviderExtensionTests.cs
    • FastMoq.Tests/ProviderTests.cs

    Reflection provider

    Provider package / namespace:

    • built into FastMoq.Core
    • namespace: FastMoq.Providers.ReflectionProvider

    Best fit:

    • dependency-light provider-neutral baseline
    • suites that want FastMoq without bringing in an external mocking library
    • tests that only need interface interception plus provider-neutral verification

    Supported capability flags:

    • invocation tracking

    Not supported by the provider capabilities:

    • call base
    • setup all properties
    • protected members
    • logger capture

    Important implementation constraints:

    • interface interception is supported through DispatchProxy
    • non-interface types fall back to public parameterless construction and do not get full interception behavior
    • reflection is the default provider when you do nothing

    Practical note:

    • this is a baseline provider, not a drop-in replacement for full Moq semantics
    • verification is best-effort: only direct method-call expressions are supported, direct constant arguments are compared with Equals(...), and richer matcher or predicate semantics are not interpreted
    • if your migrated tests rely on GetMock<T>(), direct Mock<T> access, Protected(), or VerifyLogger(...), they should not stay on reflection

    If argument intent matters beyond direct constant equality, prefer a provider that exposes richer matcher behavior or assert on the observable result instead of treating reflection verification as equivalent to Moq or NSubstitute matcher semantics.

    Recommended style:

    using var providerScope = MockingProviderRegistry.Push("reflection");
    var dependency = Mocks.GetOrCreateMock<IOrderGateway>();
    
    dependency.Instance.Publish("alpha");
    
    Mocks.Verify<IOrderGateway>(x => x.Publish("alpha"), TimesSpec.Once);
    Mocks.VerifyNoOtherCalls<IOrderGateway>();
    

    Repo-backed references:

    • FastMoq.Tests/ProviderTests.cs

    Custom providers

    Custom providers should document the same things this page documents for the built-in ones:

    • capability flags from IMockingProviderCapabilities
    • supported tracked-mock convenience APIs, if any
    • known unsupported behaviors
    • migration caveats for provider-specific patterns

    Important extension-model note:

    • the built-in providers are not inheritance extension points
    • if you want custom behavior, implement a new IMockingProvider
    • when the change is incremental rather than a full rewrite, prefer a wrapper or decorator provider that delegates to an existing provider and adjusts only the behavior you need
    • provider-authored tracked helpers can opt into additional FastMoq-owned behavior by implementing optional extension interfaces such as ITrackedMockPropertyConfigurator on the provider and exposing the creating provider through IProviderBoundFastMock on the wrapper

    If your team writes its own provider, treat this matrix format as the minimum documentation bar.

    Recommended documentation pattern

    For future provider docs, keep the structure consistent:

    1. What the provider is for.
    2. Which IMockingProviderCapabilities flags are true or false.
    3. Which provider-specific helpers or namespaces are required.
    4. Which common test shapes still need a different provider.

    That keeps migration guidance, provider selection, and provider-specific limitations aligned instead of scattering the rules across multiple pages.

    In this article
    Back to top
    Generated 2026-04-29 03:53 UTC