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:
// 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
Mocks.GetOrCreateMock<ICustomerCsvParser>()
.Setup(x => x.Parse(csv))
.Returns(rows);
var importedCount = await Component.ImportAsync(filePath, CancellationToken.None);
Mocks.Verify<ICustomerRepository>(
x => x.UpsertAsync(It.IsAny<IReadOnlyList<CustomerImportRow>>(), CancellationToken.None),
TimesSpec.Once);
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.
This guide is intentionally the "how to" companion to the repo README. The README is the better first read when you are deciding whether FastMoq is the right fit. This guide is the better first read when you already want to write a test.
For the repo-native testing conventions and framework-specific guidance used by this codebase, see the FastMoq Testing Guide.
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 Current Repo.
If you need to choose or bootstrap a provider explicitly, see the Provider Selection Guide.
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:
Package choices
Use this table when you are deciding which package line your test project should reference.
| If you want... | Install... | Why |
|---|---|---|
| simplest all-in-one experience | FastMoq |
Aggregate package that includes the primary runtime, database helpers, and web support |
| lighter core-only usage | FastMoq.Core |
Provider-first runtime without the extra EF or web-specific helper packages |
DbContext and EF-specific helpers while using FastMoq.Core |
FastMoq.Database |
Adds GetMockDbContext<TContext>() and the explicit DbContext handle modes |
controller, HttpContext, IHttpContextAccessor, or claims-principal helpers while using FastMoq.Core |
FastMoq.Web |
Adds CreateHttpContext(...), CreateControllerContext(...), SetupClaimsPrincipal(...), AddHttpContext(...), and AddHttpContextAccessor(...) |
| Moq-specific tracked-mock extension methods during migration | FastMoq.Provider.Moq |
Adds provider-package extension methods such as AsMoq(), Setup(...), SetupGet(...), SetupSequence(...), and Protected() on IFastMock<T> |
| optional NSubstitute-backed provider support | FastMoq.Provider.NSubstitute |
Adds the NSubstitute provider package and tracked-mock extensions such as AsNSubstitute() |
Important package boundaries in the current v4 line:
FastMoqalready includes the common end-user surface, including web and database helpersFastMoq.Corestays lighter on purpose, so EF helpers and web helpers are separate package decisions when you consume core directlyFastMoq.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 unsure whether your web tests need another package, see the web-helper notes in Testing Guide and the migration-specific notes in Migration Guide
.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.Database
dotnet add package FastMoq.Web
dotnet add package FastMoq.Provider.Moq
Package Manager Console
Install-Package FastMoq
PackageReference
<PackageReference Include="FastMoq" Version="4.*" />
Split-package example:
<PackageReference Include="FastMoq.Core" Version="4.*" />
<PackageReference Include="FastMoq.Database" Version="4.*" />
<PackageReference Include="FastMoq.Web" Version="4.*" />
<PackageReference Include="FastMoq.Provider.Moq" 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 repository,GetMockDbContext<TContext>()keeps the sameFastMoqnamespace call shape, but directFastMoq.Coreconsumers should addFastMoq.Databasefor EF-specific helpers. Direct web-helper consumers should addFastMoq.Web.
In the current v4 transition layout, 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 registered with MockingProviderRegistry. 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, and DbContextTestMode.RealInMemory is the real EF-backed option. The mocked-sets implementation still uses the existing moved Moq-based DbContextMock<TContext> path internally.
Required Using Statements
For most FastMoq tests, these using statements are a good starting point:
using FastMoq;
using FastMoq.Extensions;
using Microsoft.Extensions.Logging;
using Moq; // Only needed when you intentionally use Moq-specific compatibility APIs.
For all FastMoq tests, these are optional and suggested, but they are not required for FastMoq:
using Xunit; // Whatever your testing framework is
using FluentAssertions; // Used in examples (free version)
FastMoq.Extensions is especially useful because it contains logger verification helpers and other testing utilities.
Your First Test
Let's create a simple service and write a test for it using FastMoq.
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
Now let's create a test using FastMoq's MockerTestBase<T>:
// Tests/FileProcessorServiceTests.cs
using FastMoq;
using FastMoq.Extensions;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Moq;
using System.IO.Abstractions;
using Xunit;
public class FileProcessorServiceTests : MockerTestBase<FileProcessorService>
{
[Fact]
public async Task ProcessFileAsync_ShouldReturnProcessedContent_WhenValidFile()
{
// Arrange
var filePath = "test.txt";
var fileContent = "hello world";
var expectedResult = "HELLO WORLD";
Mocks.GetOrCreateMock<IFileSystem>()
.Setup(x => x.File.Exists(filePath))
.Returns(true);
Mocks.GetOrCreateMock<IFileSystem>()
.Setup(x => x.File.ReadAllTextAsync(filePath, It.IsAny<CancellationToken>()))
.ReturnsAsync(fileContent);
// Act
var result = await Component.ProcessFileAsync(filePath);
// Assert
result.Should().Be(expectedResult);
// Verify interactions
Mocks.Verify<IFileSystem>(
x => x.File.ReadAllTextAsync(filePath, It.IsAny<CancellationToken>()),
TimesSpec.Once);
}
[Fact]
public async Task ProcessFileAsync_ShouldReturnEmpty_WhenInvalidFile()
{
// Arrange
var filePath = "nonexistent.txt";
Mocks.GetOrCreateMock<IFileSystem>()
.Setup(x => x.File.Exists(filePath))
.Returns(false);
// Act
var result = await Component.ProcessFileAsync(filePath);
// Assert
result.Should().BeEmpty();
// Verify logging
Mocks.VerifyLogged(LogLevel.Warning, "not found", 1);
// Verify file was never read
Mocks.Verify<IFileSystem>(
x => x.File.ReadAllTextAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()),
TimesSpec.NeverCalled);
}
}
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
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());
}
}
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>()
.WithMessage($"*{parameterName}*");
});
}
Async Method Testing
FastMoq works seamlessly with async methods:
[Fact]
public async Task ProcessFileAsync_ShouldReturnProcessedContent()
{
// Arrange
var filePath = "data.txt";
var expectedContent = "PROCESSED DATA";
Mocks.GetOrCreateMock<IFileSystem>()
.Setup(x => x.File.Exists(filePath))
.Returns(true);
Mocks.GetOrCreateMock<IFileSystem>()
.Setup(x => x.File.ReadAllTextAsync(filePath, It.IsAny<CancellationToken>()))
.ReturnsAsync("processed data");
// Act
var result = await Component.ProcessFileAsync(filePath);
// Assert
result.Should().Be(expectedContent);
}
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 FluentAssertions for more readable 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.
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.