Skip to main content

Setup & Stubbing

Methods are called directly on Mock<T> — the chain method (.Returns(), .Throws(), etc.) makes it a setup.

Method Setup

Return Values

// Fixed return value
mock.GetUser(Any()).Returns(new User("Alice"));

// Computed return value
mock.GetUser(Any()).Returns(() => new User(DateTime.Now.ToString()));

// Async methods — no special API needed
mock.GetUserAsync(Any()).Returns(new User("Alice"));
// TUnit.Mocks auto-wraps the value in Task<T> or ValueTask<T>

Throwing Exceptions

// Throw a specific exception type
mock.Delete(Any()).Throws<InvalidOperationException>();

// Throw a specific instance
mock.Delete(Any()).Throws(new ArgumentException("bad id"));

Callbacks

// Simple callback
var callCount = 0;
mock.Process(Any())
.Callback(() => callCount++);

// Callback with access to arguments
mock.Process(Any())
.Callback((object?[] args) => Console.WriteLine($"Called with: {args[0]}"));

Sequential Behaviors

Use .Then() to define different behaviors for successive calls:

mock.GetValue(Any())
.Throws<InvalidOperationException>() // 1st call: throws
.Then()
.Returns("retry-succeeded") // 2nd call: returns value
.Then()
.Returns("cached"); // 3rd+ calls: returns this value

// Shorthand for sequential return values
mock.GetValue(Any())
.ReturnsSequentially("first", "second", "third");
// 1st: "first", 2nd: "second", 3rd+: "third" (last value repeats)

Void Methods

Void methods support Callback and Throws (but not Returns):

mock.Log(Any())
.Callback(() => { /* side effect */ });

mock.Log(Any())
.Throws<NotSupportedException>();

Void methods are also eagerly registered — calling mock.Log(Any()) without chaining is sufficient to "allow" the call in strict mode.

Property Setup

TUnit.Mocks uses C# 14 extension properties for a natural property API. The default behavior targets the getter (the most common case).

Getter Setup

// These are equivalent — both configure the getter
mock.Name.Returns("Alice");
mock.Name.Getter.Returns("Alice");

All method setup operations work on getters:

mock.Name.Throws<InvalidOperationException>();
mock.Name.Callback(() => Console.WriteLine("Name accessed"));
mock.Name.ReturnsSequentially("first", "second");

Setter Setup

// React to any value being set
mock.Count.Setter.Callback(() => Console.WriteLine("Count was set"));

// React to a specific value being set
mock.Count.Set(Is(42)).Callback(() => Console.WriteLine("Count set to 42"));

// Throw on setter
mock.Name.Setter.Throws<NotSupportedException>();

Auto-Tracking Properties

Call SetupAllProperties() to make properties behave like real auto-properties — setters store values, getters return them:

var mock = Mock.Of<IEntity>();
Mock.SetupAllProperties(mock);

mock.Object.Name = "Alice";
var name = mock.Object.Name; // "Alice"

mock.Object.Count = 10;
var count = mock.Object.Count; // 10

Explicit setups take precedence over auto-tracked values.

Out and Ref Parameters

Out parameters are excluded from setup signatures. Use the generated strongly-typed .SetsOut{Name}() methods to assign their values:

// Strongly-typed — named after the parameter, compile-time safe
mock.TryGet("key")
.Returns(true)
.SetsOutValue("found-value");

bool found = svc.TryGet("key", out var value);
// found == true, value == "found-value"

Ref parameters are included in setup signatures and participate in argument matching. Use .SetsRef{Name}() to assign output values:

mock.Swap(Any())
.SetsRefValue(99);

int val = 42;
svc.Swap(ref val);
// val == 99

The method names are derived from the original parameter names — e.g. out string value produces .SetsOutValue(), ref int count produces .SetsRefCount(). This gives you IntelliSense discoverability and compile-time type safety.

The untyped .SetsOutParameter(index, value) overload remains available for advanced scenarios but is hidden from IntelliSense on typed wrappers.

Partial Mocks

Partial mocks wrap a real class. Unconfigured method calls execute the base implementation:

public abstract class Calculator
{
public virtual int Add(int a, int b) => a + b;
public abstract int Multiply(int a, int b);
}

var mock = Mock.OfPartial<Calculator>();
mock.Multiply(Any(), Any()).Returns(99);

mock.Object.Add(2, 3); // 5 (base implementation)
mock.Object.Multiply(2, 3); // 99 (mocked)

Pass constructor arguments for non-default constructors:

var mock = Mock.OfPartial<MyService>("connectionString", 42);

Delegate Mocking

Mock any delegate type:

var mock = Mock.OfDelegate<Func<string, int>>();
mock.Invoke(Any()).Returns(42);

Func<string, int> func = mock;
var result = func("hello"); // 42

Works with Action<>, Func<>, and custom delegate types.

Wrapping Real Objects

Wrap a real instance to selectively override methods while delegating unconfigured calls to the real implementation:

var realService = new ProductionService();
var mock = Mock.Wrap(realService);

// Override just one method
mock.GetConfig().Returns(new TestConfig());

// All other calls go to realService
mock.Object.DoWork(); // calls realService.DoWork()

Multi-Interface Mocks

Create a single mock that implements multiple interfaces:

var mock = Mock.Of<ILogger, IDisposable>();

mock.Log(Any()); // ILogger method
mock.Object.Log("test");

((IDisposable)mock.Object).Dispose(); // IDisposable method

Supports up to 4 interfaces: Mock.Of<T1, T2, T3, T4>().

Setup Chaining

Setup methods return chain objects that support additional behaviors:

mock.Process(Any())
.Returns(true)
.RaisesProcessCompleted(EventArgs.Empty) // strongly-typed auto-raise event
.TransitionsTo("processed"); // state machine transition

The typed .Raises{EventName}() methods provide IntelliSense and compile-time safety for event parameters. The string-based .Raises(eventName, args) overload is also available.

See Advanced Features for details on events and state machines.