Getting Started with FastMoq
Welcome to FastMoq. This guide walks through setup and a first test using the current v4 release line. FastMoq helps you create tests with automatic dependency injection, mock tracking, and test-focused object creation without forcing you to wire every dependency by hand.
What is FastMoq?
FastMoq is designed to reduce the boilerplate usually required when setting up unit tests. It automatically creates and injects test doubles, lets you override only the parts that matter, and supports both provider-neutral test patterns and provider-specific compatibility for migration scenarios.
Why teams use FastMoq instead of using a mock provider directly
The main value is still less test harness code.
With a mock provider used directly, the test usually needs to do all of this itself:
- declare each dependency mock
- construct the subject under test manually
- keep constructor wiring in sync as dependencies change
- add extra harness code for framework-heavy types and logging
With FastMoq, the test usually only configures the dependencies that matter for the behavior under test.
Side-by-side example:
This comparison uses the optional Moq-fluent path on the FastMoq side to keep the contrast obvious. The first copy-paste example that works under the default provider appears later under Your First Test.
// Direct mock-provider usage
var parser = new Mock<ICustomerCsvParser>();
var repository = new Mock<ICustomerRepository>();
var logger = new Mock<ILogger<CustomerImportService>>();
var component = new CustomerImportService(parser.Object, repository.Object, logger.Object);
parser.Setup(x => x.Parse(csv)).Returns(rows);
var importedCount = await component.ImportAsync(filePath, CancellationToken.None);
repository.Verify(x => x.UpsertAsync(It.IsAny<IReadOnlyList<CustomerImportRow>>(), CancellationToken.None), Times.Once);
// FastMoq with optional Moq-fluent setup
Mocks.GetOrCreateMock<ICustomerCsvParser>()
.Setup(x => x.Parse(csv))
.Returns(rows);
var importedCount = await Component.ImportAsync(filePath, CancellationToken.None);
Mocks.Verify<ICustomerRepository>(
x => x.UpsertAsync(FastArg.Any<IReadOnlyList<CustomerImportRow>>(), CancellationToken.None),
TimesSpec.Once);
When the test has already moved to provider-first Mocks.Verify<T>(...) or MockingProviderRegistry.Default.Verify(...), prefer FastArg matchers inside that verification expression instead of It.IsAny(...) or It.Is(...).
FastMoq is most valuable when the subject has multiple dependencies, when constructor signatures change frequently, or when your tests repeatedly need built-in framework helpers.
Read the repo README first if you are still deciding whether FastMoq is the right fit. Use this guide once you are ready to install packages and write tests.
For the repo-native testing conventions and framework-specific guidance used by this codebase, see the FastMoq Testing Guide.
When you are deciding whether a test should stay plain, use direct Mocker usage, or move into a shared harness or wrapper layer, start with Choose The Narrowest Harness and Local Wrapper Boundary.
If you want reusable AI workflows for new tests, modernization, or migration work instead of writing prompts from scratch, see AI Prompt Templates.
If you want examples that run directly in this repository instead of static snippets only, see Executable Testing Examples.
If you are updating older FastMoq usage from the last public 3.0.0 release, see Migration Guide: 3.0.0 To The Current v4 Line.
If you need to choose or bootstrap a provider explicitly, see the Provider Selection Guide.
Read This Guide In Order
- Choose the package line you want under
Installation. - Stay on the default provider-neutral path unless you specifically need provider-native arrange syntax such as
.Setup(...). - Work through
Your First Testfirst, because that example runs under the defaultreflectionprovider without assembly-level Moq registration. - Only opt into the Moq-fluent path after reading the provider-selection note below.
Key Benefits
- Automatic Mock Creation: No need to manually declare and setup mocks
- Dependency Injection: Automatically resolves and injects dependencies into your components
- Fluent API: Clean, readable syntax for test setup and verification
- Provider Architecture: Extensible system for custom mock configurations
- Built-in Helpers: Common patterns for EF Core, HttpClient, IFileSystem, and more
- Less Constructor Wiring: The test stays focused on the behavior under test instead of the dependency graph
Installation
Install FastMoq using your preferred package manager:
Optional assertion packages
FastMoq does not require a specific assertion library.
If you want the fluent .Should() syntax used in several examples below, install AwesomeAssertions:
dotnet add package AwesomeAssertions --version 9.4.0
If your project uses Shouldly instead, install Shouldly and translate the assertion syntax accordingly:
dotnet add package Shouldly --version 4.3.0
Package choices
Use this package and namespace quick reference when you are deciding which package line your test project should reference.
| If you want... | Install... | Main namespace(s) to import | Why |
|---|---|---|---|
| simplest all-in-one experience | FastMoq |
FastMoq, FastMoq.Extensions, plus any included helper namespaces such as FastMoq.Web.Extensions, FastMoq.AzureFunctions.Extensions, and FastMoq.Azure.* |
Aggregate package that includes the primary runtime, shared Azure SDK helpers, database helpers, web support, Azure Functions helpers, and the FastMoq analyzer pack by default |
| lighter core-only usage | FastMoq.Core |
FastMoq, FastMoq.Extensions |
Provider-first runtime without the extra EF or web-specific package payloads |
| custom provider or advanced extension authoring | FastMoq.Abstractions |
FastMoq.Providers |
Shared provider contracts such as IMockingProvider, IFastMock, TimesSpec, and provider-registration attributes. Most test projects do not need to reference this package directly |
Azure SDK credentials, pageable builders, or Azure-oriented DI/config helpers while using FastMoq.Core |
FastMoq.Azure |
FastMoq.Azure.Credentials, FastMoq.Azure.DependencyInjection, FastMoq.Azure.Storage, FastMoq.Azure.KeyVault, FastMoq.Azure.Pageable |
Adds PageableBuilder, token/default-credential helpers, Azure-oriented configuration/service-provider helpers, and common Azure client registration helpers |
Azure Functions worker helpers while using FastMoq.Core |
FastMoq.AzureFunctions |
FastMoq.AzureFunctions.Extensions, FastMoq.AzureFunctions.Http |
Adds CreateFunctionContextInstanceServices(...), AddFunctionContextInstanceServices(...), CreateHttpRequestData(...), CreateHttpResponseData(...), and body readers in FastMoq.AzureFunctions.Extensions while keeping the typed IServiceProvider helpers in core |
DbContext and EF-specific helpers while using FastMoq.Core |
FastMoq.Database |
FastMoq |
Adds GetMockDbContext<TContext>() and the explicit DbContext handle modes |
controller, HttpContext, IHttpContextAccessor, or claims-principal helpers while using FastMoq.Core |
FastMoq.Web |
FastMoq.Web.Extensions, FastMoq.Web |
Adds CreateHttpContext(...), CreateControllerContext(...), SetupClaimsPrincipal(...), AddHttpContext(...), and AddHttpContextAccessor(...) |
| Moq-specific tracked-mock extension methods during migration | FastMoq.Provider.Moq |
FastMoq.Providers.MoqProvider, FastMoq.Extensions |
Adds provider-package extension methods such as AsMoq(), Setup(...), SetupGet(...), SetupSequence(...), and Protected() on IFastMock<T> |
| optional NSubstitute-backed provider support | FastMoq.Provider.NSubstitute |
FastMoq.Providers.NSubstituteProvider |
Adds the NSubstitute provider package and tracked-mock extensions such as AsNSubstitute() |
| analyzer guidance without the core or aggregate runtime package | FastMoq.Analyzers |
none at runtime | Standalone Roslyn analyzers and code fixes for migration cleanup and provider-first test-authoring guidance |
Use the table above as the quick namespace reference. The more detailed helper-namespace inventory appears below in Common Using Statements.
Important package boundaries in the current v4 line:
FastMoq already includes the common end-user surface, including shared Azure SDK helpers, web, database, and Azure Functions helpers
FastMoqandFastMoq.Coreboth include the FastMoq analyzer assets by default so most test projects get migration guidance without extra setupFastMoq.Corekeeps the provider-neutral runtime separate from the shared Azure SDK, EF, Azure Functions, and web helper packages when you consume core directlyFastMoq.Analyzersremains useful when you want the diagnostics without taking either the aggregate or core runtime package- if a core-only test project stays on the legacy Moq-shaped path with
GetMock<T>(),VerifyLogger(...),MockModel.Mock,SetupSet(...),SetupAllProperties(), or other Moq-specific compatibility flows, addFastMoq.Provider.Moqexplicitly for the extension methods and namespaces; a single visible Moq provider can be enough, but selectmoqat assembly scope when the suite should not depend on discovery remaining unambiguous FastMoq.Coreincludes the built-inreflectionprovider and the bundled Moq compatibility runtime, but the Moq tracked-mock extension methods such asSetup(...)andProtected()still belong to theFastMoq.Provider.Moqpackage- provider-package extension methods still follow the provider-package docs and selection rules described in Provider Selection and Setup
- if you are wiring Azure SDK clients, pageable sequences, or token credentials through tests while consuming
FastMoq.Coredirectly, addFastMoq.Azure - if you are wiring Azure Functions worker tests through
FunctionContext.InstanceServicesor concrete HTTP-trigger request and response objects, addFastMoq.AzureFunctionswhen you consumeFastMoq.Coredirectly - if you are unsure whether your web tests need another package, see the web-helper notes in Testing Guide and the migration-specific notes in Framework and web helper migration
- for the full analyzer catalog and package-aware migration guidance, see Migration Guide
EF Core package topology and version alignment
The aggregate FastMoq package intentionally includes FastMoq.Database, and that helper package brings EF Core test-helper dependencies such as Microsoft.EntityFrameworkCore.InMemory.
That is convenient when you want the umbrella package, but it matters if the same test project already pins relational or provider-specific EF Core packages on another major version.
Use this rule:
- keep
FastMoqwhen you want the umbrella package and the EF Core major versions across your graph already align - prefer
FastMoq.Coreplus only the helper packages you actually need when you do not want the EF-specific helper dependency surface - if you intentionally combine the aggregate
FastMoqpackage with separate EF Core provider packages, align the EF Core major versions across the graph
Mixed-major EF Core graphs often surface as runtime failures that look unrelated to FastMoq at first, such as missing-method, assembly-load, or provider-registration errors.
If your team wants the aggregate runtime package without analyzer diagnostics in a specific test project, you can opt out with:
<PackageReference Include="FastMoq" Version="4.*" ExcludeAssets="analyzers" />
.NET CLI
dotnet add package FastMoq
If you prefer the split packages instead of the aggregate package:
dotnet add package FastMoq.Core
dotnet add package FastMoq.Azure
dotnet add package FastMoq.AzureFunctions
dotnet add package FastMoq.Database
dotnet add package FastMoq.Web
# choose the provider package your tests actually use
dotnet add package FastMoq.Provider.Moq
# or
# dotnet add package FastMoq.Provider.NSubstitute
Package Manager Console
Install-Package FastMoq
PackageReference
<PackageReference Include="FastMoq" Version="4.*" />
Split-package example:
<PackageReference Include="FastMoq.Core" Version="4.*" />
<PackageReference Include="FastMoq.Azure" Version="4.*" />
<PackageReference Include="FastMoq.AzureFunctions" Version="4.*" />
<PackageReference Include="FastMoq.Database" Version="4.*" />
<PackageReference Include="FastMoq.Web" Version="4.*" />
<!-- choose the provider package your tests actually use -->
<PackageReference Include="FastMoq.Provider.Moq" Version="4.*" />
<!-- or -->
<!-- <PackageReference Include="FastMoq.Provider.NSubstitute" Version="4.*" /> -->
Note: this guide targets the current v4 release line. For the release delta relative to the last public
3.0.0package, see What's New Since 3.0.0. Note: in the current v4 package line,GetMockDbContext<TContext>()keeps the sameFastMoqnamespace call shape, but directFastMoq.Coreconsumers should addFastMoq.Databasefor EF-specific helpers. Direct shared Azure SDK helper consumers should addFastMoq.Azure. Direct Azure Functions helper consumers should addFastMoq.AzureFunctions. Direct web-helper consumers should addFastMoq.Web.
In the current v4 release line, FastMoq.Core bundles the built-in moq provider and the internal reflection fallback. The default provider is reflection. Optional providers such as nsubstitute can be added explicitly and then selected by their canonical name once the package is present, or registered manually under a custom alias. You can also register your own provider by implementing IMockingProvider; the bundled providers are examples, not the only supported choices.
The DbContext helper path now exposes explicit modes through GetDbContextHandle<TContext>(...). GetMockDbContext<TContext>() remains the mocked-sets convenience entry point, DbContextTestMode.RealInMemory is the real EF-backed option, and provider-first APIs such as GetOrCreateMock<TContext>() and GetMockModel<TContext>() return the same tracked context after the helper creates it.
Common Using Statements
FastMoq itself does not require an assertion library.
For a typical external test project, this is the main FastMoq namespace to import:
using FastMoq;
Add the other namespaces only when your test code actually uses the corresponding APIs:
using FastMoq.Extensions; // Core helper extensions such as VerifyLogged(...), AddServiceProvider(...), and CreateHttpClient(...)
using Microsoft.Extensions.Logging; // ILogger<T> or LogLevel in your test or component
using AwesomeAssertions; // If you use AwesomeAssertions in your assertions
using Shouldly; // If your project uses Shouldly instead
using Xunit; // Example only; replace with the test framework namespace your project uses
Mocker and MockerTestBase<T> live in FastMoq.
FastMoq.Extensions is the shared core helper namespace. It is optional and includes helpers such as VerifyLogged(...), AddServiceProvider(...), AddMethodResult(...), AddMethodResultAsync(...), AddMethodCompletionAsync(...), AddMethodCallback(...), AddMethodCallbackAsync(...), AddMethodException(...), AddMethodExceptionAsync(...), AddPropertyState(...), AddPropertySetterCapture(...), and CreateHttpClient(...).
If you intentionally want Moq-specific tracked .Setup(...), SetupSequence(...), or Protected() syntax, add the provider package first. A single visible Moq provider can be enough, but select or register moq explicitly before copying those examples when the suite should not depend on discovery remaining unambiguous:
dotnet add package FastMoq.Provider.Moq
FastMoq.Provider.Moq already brings Moq transitively. Add a top-level Moq package reference only when you intentionally need to pin or override the transitive Moq version.
using FastMoq.Providers;
[assembly: FastMoqDefaultProvider("moq")]
You can use [assembly: FastMoqRegisterProvider("moq", typeof(MoqMockingProvider), SetAsDefault = true)] instead when you want registration and selection in one attribute.
FastMoq does not place every extension API in FastMoq.Extensions. The consumer-facing helper namespaces are:
| Namespace | Package | Purpose |
|---|---|---|
FastMoq.Extensions |
FastMoq or FastMoq.Core |
Core helper extensions for logger verification, typed IServiceProvider setup, property-state helpers, constructor and object helpers, HTTP helpers, and related test utilities. Installing FastMoq.Provider.Moq also adds the Moq HTTP compatibility helpers to this same namespace. |
FastMoq.Web.Extensions |
FastMoq.Web or FastMoq |
ASP.NET Core web-test helpers such as HttpContext, controller-context, and claims-principal setup. |
FastMoq.AzureFunctions.Extensions |
FastMoq.AzureFunctions or FastMoq |
Azure Functions worker helpers such as FunctionContext.InstanceServices, HttpRequestData, HttpResponseData, and request/response body helpers. |
FastMoq.Azure.Credentials |
FastMoq.Azure or FastMoq |
Azure credential registration helpers for TokenCredential and DefaultAzureCredential-shaped tests. |
FastMoq.Azure.DependencyInjection |
FastMoq.Azure or FastMoq |
Azure-oriented configuration, DI, and typed service-provider helpers. |
FastMoq.Azure.Storage |
FastMoq.Azure or FastMoq |
Azure Storage client registration helpers for blob, queue, and table clients. |
FastMoq.Azure.KeyVault |
FastMoq.Azure or FastMoq |
Azure Key Vault SecretClient registration helpers. |
FastMoq.Azure.Pageable |
FastMoq.Azure or FastMoq |
Azure SDK pageable helpers such as PageableBuilder. This is helper surface rather than extension-method surface, but consumers still import the namespace directly. |
FastMoq.Providers.MoqProvider |
FastMoq.Provider.Moq |
Moq-specific tracked-mock escape hatches such as AsMoq(), Setup(...), SetupGet(...), SetupSequence(...), and Protected(). |
FastMoq.Providers.NSubstituteProvider |
FastMoq.Provider.NSubstitute |
NSubstitute-specific tracked-mock escape hatches such as AsNSubstitute(), Received(...), and DidNotReceive(). |
Azure Functions also exposes non-extension builder helpers in FastMoq.AzureFunctions.Http when you want the concrete request and response builders directly.
Your First Test
Let's create a simple service and write a test for it using FastMoq.
The snippets below use xUnit attributes only as one example of test-framework syntax. The FastMoq APIs shown here are not tied to xUnit, so keep the FastMoq calls and use the test framework your project already standardizes on.
1. Create a Service to Test
First, let's create a simple file processing service that depends on the IFileSystem interface:
// Services/FileProcessorService.cs
using System.IO.Abstractions;
using Microsoft.Extensions.Logging;
public interface IFileProcessorService
{
Task<string> ProcessFileAsync(string filePath);
bool ValidateFilePath(string filePath);
}
public class FileProcessorService : IFileProcessorService
{
private readonly IFileSystem _fileSystem;
private readonly ILogger<FileProcessorService> _logger;
public FileProcessorService(IFileSystem fileSystem, ILogger<FileProcessorService> logger)
{
_fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task<string> ProcessFileAsync(string filePath)
{
if (!ValidateFilePath(filePath))
{
_logger.LogWarning("Invalid file path: {FilePath}", filePath);
return string.Empty;
}
_logger.LogInformation("Processing file: {FilePath}", filePath);
var content = await _fileSystem.File.ReadAllTextAsync(filePath);
var processedContent = content.ToUpperInvariant();
_logger.LogInformation("File processed successfully: {FilePath}", filePath);
return processedContent;
}
public bool ValidateFilePath(string filePath)
{
return !string.IsNullOrWhiteSpace(filePath) && _fileSystem.File.Exists(filePath);
}
}
2. Write Your First FastMoq Test
Start with a provider-neutral example that works under the default reflection provider. This path does not require FastMoq.Provider.Moq, Moq, or assembly-level Moq registration.
This sample uses AwesomeAssertions for the assertion syntax and VerifyLogged(...) for log verification, so it also includes those optional namespaces.
// Tests/FileProcessorServiceTests.cs
using FastMoq;
using FastMoq.Extensions;
using Microsoft.Extensions.Logging;
using AwesomeAssertions;
using System.IO.Abstractions;
using Xunit;
public class FileProcessorServiceTests : MockerTestBase<FileProcessorService>
{
[Fact]
public async Task ProcessFileAsync_ShouldReturnProcessedContent_WhenValidFile()
{
// Arrange
var filePath = @"c:\temp\test.txt";
var fileSystem = Mocks.GetObject<IFileSystem>();
fileSystem.File.WriteAllText(filePath, "hello world");
// Act
var result = await Component.ProcessFileAsync(filePath);
// Assert
result.Should().Be("HELLO WORLD");
Mocks.VerifyLogged(LogLevel.Information, "File processed successfully", 1);
}
[Fact]
public async Task ProcessFileAsync_ShouldReturnEmpty_WhenInvalidFile()
{
// Arrange
var filePath = @"c:\temp\missing.txt";
// Act
var result = await Component.ProcessFileAsync(filePath);
// Assert
result.Should().BeEmpty();
Mocks.VerifyLogged(LogLevel.Warning, "Invalid file path", 1);
}
}
3. Optional: Moq-fluent setup path
If you prefer tracked .Setup(...) syntax, opt into it explicitly first. This is the path that requires FastMoq.Provider.Moq, Moq, the FastMoq.Providers.MoqProvider namespace, and assembly-level provider selection.
using FastMoq;
using FastMoq.Extensions;
using FastMoq.Providers;
using FastMoq.Providers.MoqProvider;
using Microsoft.Extensions.Logging;
using Moq;
using AwesomeAssertions;
using System.IO.Abstractions;
using Xunit;
[assembly: FastMoqDefaultProvider("moq")]
public class FileProcessorServiceMoqTests : MockerTestBase<FileProcessorService>
{
[Fact]
public async Task ProcessFileAsync_ShouldReturnProcessedContent_WhenValidFile()
{
var filePath = "test.txt";
Mocks.GetOrCreateMock<IFileSystem>()
.Setup(x => x.File.Exists(filePath))
.Returns(true);
Mocks.GetOrCreateMock<IFileSystem>()
.Setup(x => x.File.ReadAllTextAsync(filePath, It.IsAny<CancellationToken>()))
.ReturnsAsync("hello world");
var result = await Component.ProcessFileAsync(filePath);
result.Should().Be("HELLO WORLD");
}
}
Understanding the FastMoq Architecture
MockerTestBase<T>
MockerTestBase<T> is the foundation of FastMoq testing. It automatically:
- Creates your component: The
Componentproperty contains an instance of your class under test - Manages dependencies: Constructor parameters are resolved automatically using FastMoq's current type-map, known-type, and auto-mock rules
- Provides mock access: Use
Mocks.GetOrCreateMock<T>()to configure tracked mock behavior - Handles cleanup: Mocks are properly disposed after each test
Key Properties and Methods
| Property/Method | Description |
|---|---|
Component |
The instance of your class under test |
MockOptional |
Obsolete compatibility alias for OptionalParameterResolution. Prefer explicit OptionalParameterResolution or InvocationOptions in new code. |
Mocks |
The Mocker instance that manages all mocks |
Mocks.GetOrCreateMock<T>() |
Gets the tracked mock handle for interface T |
Mocks.GetObject<T>() |
Gets the mocked object instance |
Automatic Dependency Resolution
FastMoq uses a smart dependency resolver that:
- Creates mocks for interfaces automatically
- Uses sensible defaults for common types (ILogger, IOptions, etc.)
- Supports complex dependency chains
- Handles circular dependencies gracefully
Advanced Setup Options
Custom Mock Configuration
The next two snippets use the optional Moq-fluent arrange path. If you want .Setup(...), make sure you already added FastMoq.Provider.Moq and selected moq for the test assembly as shown above.
If you need to configure mocks before your component is created, use the SetupMocksAction:
public class OrderServiceTests : MockerTestBase<OrderService>
{
protected override Action<Mocker> SetupMocksAction => mocker =>
{
// Configure mock behavior before component creation
mocker.GetOrCreateMock<IPaymentProcessor>()
.Setup(x => x.ValidateCard(It.IsAny<string>()))
.Returns(true);
};
[Fact]
public void TestWithPreConfiguredMocks()
{
// Your test here - mocks are already configured
}
}
Constructor Injection Control
You can also configure mock setup through the base constructor:
public class OrderServiceTests : MockerTestBase<OrderService>
{
public OrderServiceTests() : base(ConfigureMocks)
{
}
private static void ConfigureMocks(Mocker mocker)
{
mocker.GetOrCreateMock<IOrderRepository>()
.Setup(x => x.GetOrderAsync(It.IsAny<int>()))
.ReturnsAsync(new Order());
}
}
When a test needs a specific constructor, prefer the explicit constructor-selection hooks instead of relying on GetObject<T>() to land on the right overload.
- For
MockerTestBase<TComponent>, overrideComponentConstructorParameterTypes. - For direct
Mockerusage, callCreateInstanceByType<T>(...). - If the chosen constructor depends on
IServiceProviderorIServiceScopeFactory, build and register a typed provider withAddServiceProvider(...)instead of extracting onlyIServiceScopeFactoryfrom a manualBuildServiceProvider()call.
internal sealed class ArchiveInvokerTests : MockerTestBase<ArchiveInvoker>
{
protected override Action<Mocker>? SetupMocksAction => mocker =>
{
var fileSystem = mocker.GetFileSystem();
mocker.AddServiceProvider(services =>
{
services.AddLogging();
services.AddOptions();
services.AddSingleton<IFileSystem>(fileSystem);
services.AddSingleton<ArchiveService>();
}, replace: true);
};
protected override Type?[]? ComponentConstructorParameterTypes =>
new Type?[] { typeof(IFileSystem), typeof(IServiceScopeFactory) };
}
Use GetFileSystem() when you want FastMoq's shared in-memory file system to flow through both constructor injection and the typed provider. Reach for AddType<IFileSystem>(...) only when you intentionally need a different IFileSystem instance than the built-in one.
See the Testing Guide for the full constructor-selection rules and the typed IServiceProvider helper guidance for framework-heavy ServiceCollection patterns.
Common Patterns
Testing Constructor Parameters
FastMoq provides helpers for testing constructor parameter validation:
[Fact]
public void Constructor_ShouldThrow_WhenFileSystemIsNull()
{
TestConstructorParameters((action, constructorName, parameterName) =>
{
action.Should()
.Throw<ArgumentNullException>()
.Which.ParamName.Should().Be(parameterName);
});
}
If you want diagnostic output while the helper runs, pass a framework-neutral line writer:
TestConstructorParameters((action, constructorName, parameterName) =>
action.EnsureNullCheckThrown(parameterName, constructorName, message => output.WriteLine(message)));
That keeps the FastMoq helper surface framework-neutral while still letting the test project adapt its local runner output.
Async Method Testing
FastMoq works seamlessly with async methods:
[Fact]
public async Task ProcessFileAsync_ShouldReturnProcessedContent()
{
// Arrange
var filePath = @"c:\temp\data.txt";
var fileSystem = Mocks.GetObject<IFileSystem>();
fileSystem.File.WriteAllText(filePath, "processed data");
// Act
var result = await Component.ProcessFileAsync(filePath);
// Assert
result.Should().Be("PROCESSED DATA");
}
Next Steps
Now that you understand the basics, explore these advanced topics:
- Cookbook - Common patterns and real-world scenarios
- Feature Parity - Compare FastMoq with other frameworks
- Sample Applications - Complete examples with Azure integration
Best Practices
- Use descriptive test names following the pattern
MethodName_ShouldExpectedBehavior_WhenCondition - Follow AAA pattern (Arrange, Act, Assert) for clarity
- Keep tests focused - test one behavior per test method
- Use one assertion style consistently within a given test project
- Match the surrounding project if it already uses fluent
.Should()assertions or Shouldly-style assertions - Include proper using statements - Always include
FastMoq.Extensionsfor logger verification helpers - Verify important interactions but avoid over-verification
- Group related tests in the same test class
- Use provider-safe logger verification with
Mocks.VerifyLogged(...)
Logger verification guidance
Prefer Mocks.VerifyLogged(...) for new code. It is provider-safe because FastMoq captures ILogger callbacks through the active IMockingProvider and verifies the captured entries in core.
If the test suite needs a first-party registration story for ILoggerFactory, ILogger, or ILogger<T>, use Mocks.AddCapturedLoggerFactory() for direct FastMoq resolution when the helper should create the capture-backed factory for you, or Mocks.CreateLoggerFactory() when you want to plug the same callback-backed factory into a typed IServiceProvider recipe. Use Mocks.AddLoggerFactory(existingFactory, replace: true) when you already have a factory instance to register. When the test also needs to mirror log output to a local sink after Mocker already exists, use the sink-aware overloads such as Mocks.AddCapturedLoggerFactory(output.WriteLine, replace: true) or Mocks.CreateLoggerFactory((logLevel, eventId, message, exception) => ...) instead of maintaining a private logger wrapper.
When the test already relies on FastMoq-managed logger mocks and only needs to mirror the normalized captured entries to a local sink, use Mocks.SetupLoggerCallback((logLevel, eventId, message, exception) => ...) instead of rebuilding the logger mock with provider-specific ILogger.Log<TState> setup code.
Use GetOrCreateMock<ILogger<T>>().AsMoq().VerifyLogger(...) only when you intentionally want the legacy Moq-specific behavior. That API is a compatibility shim and is planned to leave core in v5.
Troubleshooting
Common Issues
Problem: System.MethodAccessException when mocking DbContext
Solution: Add [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] to your AssemblyInfo.cs
Problem: Mock not being created for optional interface parameter
Solution: Set Mocks.OptionalParameterResolution = OptionalParameterResolutionMode.ResolveViaMocker before creating the SUT. MockOptional = true is obsolete and only retained as a compatibility alias.
Problem: Component constructor throws exception
Solution: Use SetupMocksAction or base constructor to configure required mocks before component creation
For more troubleshooting tips, see the FAQ.