Skip to main content

TUnit.Mocks

TUnit.Mocks is a standalone, source-generated, AOT-compatible mocking framework. Because mocks are generated at compile time, it works with Native AOT, trimming, and single-file publishing — unlike traditional mocking libraries that rely on runtime proxy generation.

While it integrates seamlessly with TUnit's assertion engine, TUnit.Mocks has no dependency on the TUnit test framework and works with any test runner — xUnit, NUnit, MSTest, or no framework at all.

Beta

TUnit.Mocks is currently in beta. The API may change before the stable release.

Installation

Add the NuGet package to your test project:

dotnet add package TUnit.Mocks --prerelease

For HTTP mocking or logging helpers, also add:

dotnet add package TUnit.Mocks.Http --prerelease
dotnet add package TUnit.Mocks.Logging --prerelease
C# 14 Required

TUnit.Mocks requires C# 14 or later (LangVersion set to 14 or preview). If your project targets an older version, you will see error TM004 at compile time.

Your First Mock

using TUnit.Mocks;

public interface IGreeter
{
string Greet(string name);
}

public class GreeterTests
{
[Test]
public async Task Greet_Returns_Configured_Value()
{
// Arrange — create a mock using the static extension syntax
var mock = IGreeter.Mock();

// Configure — set up a return value
mock.Greet(Any()).Returns("Hello!");

// Act — mock IS the interface, no .Object needed
IGreeter greeter = mock;
var result = greeter.Greet("Alice");

// Assert — verify the result and the call
await Assert.That(result).IsEqualTo("Hello!");
mock.Greet("Alice").WasCalled(Times.Once);
}
}

The Mock.Of<T>() factory is also available as an alternative syntax:

var mock = Mock.Of<IGreeter>(); // equivalent to IGreeter.Mock()

Key Concepts

Creating Mocks

Factory MethodUse Case
T.Mock()Mock an interface, abstract class, or concrete class — the recommended syntax (details)
Mock.OfDelegate<T>()Mock a delegate (Func<>, Action<>, etc.)
Mock.Wrap<T>(instance)Wrap a real object with selective overrides
Mock.Of<T1, T2>()Mock multiple interfaces on a single object
[GenerateMock(typeof(T))]Generate a mock for interfaces with static abstract members (details)
Mock.HttpHandler()Create a MockHttpHandler (requires TUnit.Mocks.Http)
Mock.HttpClient(baseAddress?)Create a MockHttpClient — an HttpClient with a .Handler property (requires TUnit.Mocks.Http)
Mock.Logger()Create a MockLogger (requires TUnit.Mocks.Logging)
Mock.Logger<T>()Create a MockLogger<T> implementing ILogger<T> (requires TUnit.Mocks.Logging)

All factory methods accept an optional MockBehavior parameter:

var loose = IService.Mock(); // loose (default)
var strict = IService.Mock(MockBehavior.Strict); // throws on unconfigured calls

The Mock Wrapper

T.Mock() returns a Mock<T> wrapper (for interfaces, a generated subclass that also implements the interface). Extension methods are generated directly on Mock<T> for each member of the mocked type, and the chain methods (.Returns(), .WasCalled(), etc.) disambiguate between setup and verification:

var mock = IService.Mock();

mock.GetUser(Any()).Returns(user); // setup — .Returns() makes it a stub
mock.GetUser(42).WasCalled(Times.Once); // verify — .WasCalled() makes it a check
mock.RaiseOnMessage("hi"); // raise events — Raise{EventName}()
mock.Object // the T instance (also available via direct cast)

Typed Mock Wrapper

For interfaces, IMyInterface.Mock() (a C# 14 static extension member) returns a specialized wrapper type that extends Mock<T> and implements the interface directly. This means the mock can be used anywhere the interface is expected — no .Object or cast needed:

var mock = IGreeter.Mock();

// mock IS an IGreeter — assign directly, pass to methods, use in collections
IGreeter greeter = mock;
List<IGreeter> greeters = [mock];
AcceptGreeter(mock);

// Setup and verification work the same way
mock.Greet(Any()).Returns("Hello!");
mock.Greet("Alice").WasCalled();

T.Mock() is the recommended syntax for all types — interfaces, abstract classes, and concrete classes. For interfaces it returns a typed wrapper; for classes it returns Mock<T>. Constructor arguments are supported as strongly-typed parameters:

var strict = IGreeter.Mock(MockBehavior.Strict);
var service = MyService.Mock("connectionString", 42);
note

T.Mock() requires C# 14 / .NET 10 or later (it uses C# 14 static extension members). For older language versions, or for multi-interface mocks, interfaces with static abstract members, delegates, and wrap mocks, use the Mock.Of<T>() / Mock.Wrap() / Mock.OfDelegate<T>() factory methods.

Implicit Conversion

Mock<T> also supports implicit conversion to T — so T.Mock() works without .Object:

var mock = IGreeter.Mock();
IGreeter greeter = mock; // implicit conversion

Loose vs Strict Mode

ModeUnconfigured methodsDefault
MockBehavior.LooseReturn smart defaults (0, "", false, null, auto-mocked interfaces)Yes
MockBehavior.StrictThrow MockStrictBehaviorExceptionNo

Concise Argument Matching

TUnit.Mocks imports matchers globally — no Arg. prefix needed. Raw values, inline lambdas, and Any() work directly as arguments:

var mock = IUserService.Mock();

// Any() — matches everything
mock.GetUser(Any()).Returns(user);

// Raw values — implicit exact matching
mock.GetUser(42).Returns(alice);

// Inline lambdas — predicate matching directly in the call
mock.GetUser(id => id > 0).Returns(validUser);
mock.GetByRole(role => role == "admin").Returns(admins);

// Mix lambdas with Any() or raw values
mock.Search(name => name.StartsWith("A"), Any()).Returns(results);

// Is<T>() — explicit predicate matching (also works)
mock.GetUser(Is<int>(id => id > 0)).Returns(validUser);

See Argument Matchers for the full API.

What's Next

  • Setup & Stubbing — configure return values, callbacks, exceptions, and property behaviors
  • Verification — verify calls, ordering, and assertion integration
  • Argument Matchers — match arguments with predicates, patterns, and capture values
  • Advanced Features — state machines, events, auto-mocking, diagnostics, and more
  • HTTP Mocking — mock HttpClient with MockHttpHandler
  • Logging — capture and verify ILogger calls with MockLogger