Advanced Features
Events
Raising Events
If the mocked interface declares events, TUnit.Mocks generates Raise{EventName}() extension methods directly on Mock<T>:
public interface IConnection
{
event EventHandler<string>? OnMessage;
event Action? OnDisconnect;
}
var mock = Mock.Of<IConnection>();
// Subscribe to the event
string? received = null;
mock.Object.OnMessage += (sender, msg) => received = msg;
// Raise the event through the mock
mock.RaiseOnMessage("Hello!");
// received == "Hello!"
Auto-Raise on Method Call
Trigger an event automatically when a method is called using the typed .Raises{EventName}() method on a setup chain:
mock.SendMessage(Any())
.RaisesOnMessage("echo");
mock.Object.SendMessage("test");
// OnMessage event fires with "echo"
The typed raise methods are generated per-event with correct parameter types, giving you IntelliSense and compile-time safety. The string-based .Raises(eventName, args) overload is still available for dynamic scenarios.
Event Subscription Tracking
Query and react to event subscriptions through the strongly-typed Events surface:
var mock = Mock.Of<IConnection>();
// Register callbacks for subscribe/unsubscribe
mock.Events.OnMessage.OnSubscribe(() => Console.WriteLine("subscribed"));
mock.Events.OnMessage.OnUnsubscribe(() => Console.WriteLine("unsubscribed"));
mock.Object.OnMessage += (s, e) => { };
// prints "subscribed"
// Query subscriber info
var wasSubscribed = mock.Events.OnMessage.WasSubscribed; // true
var count = mock.Events.OnMessage.SubscriberCount; // 1
State Machine Mocking
Model stateful behavior where method responses depend on the mock's current state:
public interface IConnection
{
string GetStatus();
void Connect();
void Disconnect();
}
var mock = Mock.Of<IConnection>();
Mock.SetState(mock, "disconnected");
Mock.InState(mock, "disconnected", m =>
{
m.GetStatus().Returns("OFFLINE");
m.Connect().TransitionsTo("connected");
});
Mock.InState(mock, "connected", m =>
{
m.GetStatus().Returns("ONLINE");
m.Disconnect().TransitionsTo("disconnected");
});
// Start disconnected
var status = mock.Object.GetStatus(); // "OFFLINE"
mock.Object.Connect(); // transitions to "connected"
status = mock.Object.GetStatus(); // "ONLINE"
mock.Object.Disconnect(); // transitions back to "disconnected"
status = mock.Object.GetStatus(); // "OFFLINE"
State API
| Method | Description |
|---|---|
Mock.SetState(mock, "name") | Set the current state |
Mock.SetState(mock, null) | Clear state (all setups match) |
Mock.InState(mock, "name", configure) | Register setups scoped to a state |
.TransitionsTo("name") | Transition state after method call (on setup chain) |
Recursive / Auto-Mocking
In loose mode, methods returning interface types automatically return functional mocks instead of null:
public interface IServiceA
{
IServiceB GetServiceB();
}
public interface IServiceB
{
int GetValue();
}
var mock = Mock.Of<IServiceA>();
// GetServiceB() automatically returns an auto-mock
var serviceB = mock.Object.GetServiceB();
// serviceB is not null — it's a working mock
// Configure the auto-mock via Mock.Get
var autoMock = Mock.Get(serviceB);
autoMock.GetValue().Returns(42);
var value = serviceB.GetValue(); // 42
Use Mock.Get(obj) to retrieve the Mock<T> wrapper for any mock object — auto-mocked return values, or any object created by Mock.Of. Auto-mocks are cached — calling the same method returns the same mock instance.
MockRepository
Manage multiple mocks with shared behavior and batch operations:
var repo = new MockRepository(MockBehavior.Strict);
var serviceMock = repo.Of<IService>();
var loggerMock = repo.Of<ILogger>();
// Configure each mock individually
serviceMock.GetData(Any()).Returns("result");
loggerMock.Log(Any());
// Exercise code
serviceMock.Object.GetData(1);
loggerMock.Object.Log("hello");
// Batch verification
repo.VerifyAll(); // all setups invoked across all mocks
repo.VerifyNoOtherCalls(); // no unverified calls on any mock
// Batch reset
repo.Reset(); // clear all mocks
Repository API
| Method | Description |
|---|---|
repo.Of<T>() | Create and track a loose mock |
repo.Of<T>(behavior) | Create and track a mock with specific behavior |
repo.OfPartial<T>(args) | Create and track a partial mock |
repo.Track(existingMock) | Add an existing mock to the repository |
repo.Mocks | All tracked mocks |
repo.VerifyAll() | Verify all setups on all mocks |
repo.VerifyNoOtherCalls() | Verify no unverified calls on any mock |
repo.Reset() | Reset all mocks |
Diagnostics
Get a diagnostic report of setup coverage and call matching:
mock.GetUser(Any()).Returns(new User("Alice"));
mock.Delete(Any());
svc.GetUser(1);
// Delete was never called
var diag = Mock.GetDiagnostics(mock);
diag.TotalSetups; // 2
diag.ExercisedSetups; // 1
diag.UnusedSetups; // [Delete(Any())]
diag.UnmatchedCalls; // [] (all calls matched a setup)
Useful for debugging why a mock isn't behaving as expected, or for finding dead setups.
Custom Default Value Provider
Override the default return values for unconfigured methods in loose mode:
public class TestDefaults : IDefaultValueProvider
{
public bool CanProvide(Type type)
=> type == typeof(string) || type == typeof(int);
public object? GetDefaultValue(Type type) => type switch
{
_ when type == typeof(string) => "test-default",
_ when type == typeof(int) => -1,
_ => null
};
}
var mock = Mock.Of<IService>();
Mock.SetDefaultValueProvider(mock, new TestDefaults());
var name = mock.Object.GetName(); // "test-default" (no setup needed)
var count = mock.Object.GetCount(); // -1
The provider is consulted before auto-mocking and built-in smart defaults.
Reset
Clear all setups, call history, state, and auto-tracked property values:
mock.GetUser(Any()).Returns(new User("Alice"));
svc.GetUser(1);
Mock.Reset(mock);
svc.GetUser(1); // returns default (setup cleared)
Mock.GetInvocations(mock).Count; // 0 (history cleared)
The SetupAllProperties() flag is preserved across resets.