MockInterceptor 1.0.0-alpha.0

This is a prerelease version of MockInterceptor.
dotnet add package MockInterceptor --version 1.0.0-alpha.0
                    
NuGet\Install-Package MockInterceptor -Version 1.0.0-alpha.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MockInterceptor" Version="1.0.0-alpha.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MockInterceptor" Version="1.0.0-alpha.0" />
                    
Directory.Packages.props
<PackageReference Include="MockInterceptor" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MockInterceptor --version 1.0.0-alpha.0
                    
#r "nuget: MockInterceptor, 1.0.0-alpha.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MockInterceptor@1.0.0-alpha.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MockInterceptor&version=1.0.0-alpha.0&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=MockInterceptor&version=1.0.0-alpha.0&prerelease
                    
Install as a Cake Tool

🎣 MockInterceptor: Non-Intrusive Mocking for Coupled Code

MockInterceptor is a C# 12 Source Generator library designed to enable dependency mocking of tightly coupled classes. By strictly adhering to the C# Interceptors method call specification, it rewrites Intermediate Language (IL) at compile time, redirecting targeted method calls to a mock proxy managed by your test framework (e.g., Moq).

💡 The Problem Solved

In tightly coupled code, internal instantiation and static calls hinder unit testing:

public class Worker
{
    private readonly Executor executor = new();

    public (string, int) DoWork() =>
        (Executor.GetVersion(), this.executor.Execute());    
}

MockInterceptor can bypasses the actual Executor code execution by transparently redirecting all method calls (GetVersion, Execute) to your mock setup.


🚀 Configuration: The Dedicated Test Build

To maintain a clean separation between development, testing, and production, we use a custom Test build configuration. This ensures the interception code is only compiled when running tests, avoiding overhead and maintaining a clean debugging experience for your regular Debug and Release builds.

1. Define the Custom Test Configuration

Ensure your solution file (.slnx) defines the Test build type alongside Debug and Release

<Configurations>
    <BuildType Name="Debug" />
    <BuildType Name="Test" /> 
    <BuildType Name="Release" />
</Configurations>

2. Configure the Target Project (.csproj)

The Target Project (containing Worker and Executor) must define the required constants and reference the generator only when the configuration is explicitly set to Test.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <InternalsVisibleTo Include="Your.Test.Project" />
  </PropertyGroup>

  <ItemGroup Condition="'$(Configuration)' == 'Test'">
    <PackageReference Include="MockInterceptor" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
  </ItemGroup>
  
</Project>


✍️ Usage Guide

1. Marking the Target Class

Guard the [Intercept] assembly attribute with the #if TEST constant to ensure it's only included in your special test build.

File: AssemblyConfig.cs (in the Target Project)

#if TEST
using MockInterceptor;

// Tells the generator to process the Executor class and all its method call sites.
[assembly: Intercept(typeof(Executor))] 
#endif

2. The Interception Mechanism Explained

The Source Generator emits interfaces and the static ExecutorInterceptor class to manage the mocks.

Target Code Interception Target Mock Management Strategy
Static Call (Executor.GetVersion()) The GetVersion() method call. Redirected to the StaticMock property (IStaticExecutor).
Instance Call (executor.Execute()) The Execute() method call. Redirected to a generated Extension Method that checks the mock state.
Constructor (new Executor()) No Direct Interception. The mock (from MockQueue) is consumed and tracked by the first instance method call (Execute()) on the newly created object.

3. Writing the TestIn your Test Project, use Moq with the generated interfaces and control the redirection via the ExecutorInterceptor's static properties

// Guarding the test class with #if TEST because ExecutorInterceptor is generated only in the test build
#if TEST
using MockInterceptor.Interceptors; // Generated namespace
using Moq;
using Xunit;

namespace MockInterceptor.Sample.Tests;

public class InterceptorTest
{
    [Fact]
    public void MockStaticAndInstance()
    {
        // 1. Reset state (Essential for test isolation)
        ExecutorInterceptor.Reset();

        // 2. Create Mocks using the generated interfaces
        var instanceMock = new Mock<IExecutor>();
        var staticMock   = new Mock<IStaticExecutor>();

        // 3. Setup mock expectations
        instanceMock.Setup(x => x.Execute()).Returns(42);
        staticMock.Setup(x => x.GetVersion()).Returns("v5");

        // --- STAGING THE MOCKS ---

        // 4. Stage the Static Mock
        ExecutorInterceptor.StaticMock = staticMock.Object; 
        
        // 5. Queue the Instance Mock (Consumed by the first instance method call)
        ExecutorInterceptor.MockQueue.Enqueue(instanceMock.Object);

        // 6. Act (Worker instantiation and calls trigger the Interceptors)
        var worker = new Worker();
        var actual = worker.DoWork(); 

        // 7. Assert
        var expected = ("v5", 42);
        Assert.Equal(expected, actual);
        
        // Verify the instance mock was called
        instanceMock.Verify(x => x.Execute(), Times.Once);
    }
}
#endif

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0-alpha.0 107 12/20/2025