diff --git a/docs/docs/migration/mocking/fakeiteasy.md b/docs/docs/migration/mocking/fakeiteasy.md
new file mode 100644
index 00000000000..0ae84d3fea4
--- /dev/null
+++ b/docs/docs/migration/mocking/fakeiteasy.md
@@ -0,0 +1,482 @@
+---
+sidebar_label: FakeItEasy
+---
+
+# Migrating from FakeItEasy to TUnit.Mocks
+
+TUnit.Mocks generates mocks at compile time instead of creating runtime proxies. FakeItEasy configures a fake through `A.CallTo(() => fake.Member(...))`. TUnit.Mocks generates a strongly typed member on the mock for each member of the mocked type, so you call `mock.Member(...)` directly. The chained method decides the meaning: `.Returns()` configures a setup, and `.WasCalled()` verifies calls.
+
+TUnit.Mocks works with any test framework. You can migrate mocks before, after, or without migrating the tests to TUnit.
+
+## Before You Start
+
+1. Add the package:
+
+ ```bash
+ dotnet add package TUnit.Mocks
+ ```
+
+2. Set `14` (or `preview`) in the test project. TUnit.Mocks requires C# 14. Older versions report error `TM004`.
+3. Read [Running Both Libraries Side by Side](#running-both-libraries-side-by-side) if you migrate one file at a time. `Times` exists in both libraries.
+
+## Quick Reference
+
+| FakeItEasy | TUnit.Mocks |
+|---|---|
+| `A.Fake()` | `IService.Mock()` |
+| `A.Fake(o => o.Strict())` | `IService.Mock(MockBehavior.Strict)` |
+| `A.Fake(o => o.WithArgumentsForConstructor(...))` | `MyClass.Mock(arg1, arg2)` |
+| `A.Fake(o => o.Implements())` | `Mock.Of()` |
+| `A.Fake(o => o.Wrapping(real))` | `Mock.Wrap(real)` (non-sealed classes only; no equivalent for interfaces) |
+| The fake passed to the code under test | `mock` (converts implicitly) or `mock.Object` |
+| `A.CallTo(() => fake.Method(1)).Returns(value)` | `mock.Method(1).Returns(value)` |
+| `.ReturnsLazily((int id) => ...)` | `.Returns((int id) => ...)` |
+| `.ReturnsNextFromSequence(a, b)` | `.ReturnsSequentially(a, b)` |
+| `.Returns(a).Once().Then.Returns(b)` | `.Returns(a).Then().Returns(b)` |
+| `.Throws()` / `.ThrowsAsync(ex)` | `.Throws()` / `.Throws(ex)` |
+| `.Invokes((int id) => ...)` | `.Callback((int id) => ...)` |
+| `.DoesNothing()` | `mock.VoidMethod(...)` with no chained behavior |
+| `.CallsBaseMethod()` | Default for class mocks |
+| `.AssignsOutAndRefParameters(value)` | `.SetsOut{ParameterName}(value)` |
+| `A.Ignored` / `A._` | `Any()` or `Any()` |
+| `A.That.Matches(x => ...)` | `x => ...` or `Is(x => ...)` |
+| `.WithAnyArguments()` | `Any()` for each parameter (see [Argument Constraints](#argument-constraints)) |
+| `.MustHaveHappened()` | `.WasCalled()` |
+| `.MustHaveHappenedOnceExactly()` | `.WasCalled(Times.Once)` |
+| `.MustNotHaveHappened()` | `.WasNeverCalled()` |
+| `A.CallToSet(() => fake.Prop).To(value)` | `mock.Prop.Set(value)` |
+| `fake.Event += Raise.With(args)` | `mock.Raise{EventName}(args)` |
+| `Fake.GetCalls(fake)` | `mock.Invocations` |
+| `Fake.ClearRecordedCalls(fake)` | `mock.Reset()` (also clears setups) |
+
+
+
+## Example Types
+
+The examples on this page use these types:
+
+```csharp
+public record User(int Id, string Name);
+
+public sealed class UserSavedEventArgs(User user) : EventArgs
+{
+ public User User { get; } = user;
+}
+
+public interface IUserRepository
+{
+ User? GetById(int id);
+ Task GetByIdAsync(int id);
+ void Save(User user);
+ bool TryGetName(int id, out string name);
+ string ConnectionName { get; set; }
+ event EventHandler? UserSaved;
+}
+
+public abstract class PriceCalculator
+{
+ public virtual decimal Tax(decimal amount) => amount * 0.2m;
+ public abstract decimal Discount(decimal amount);
+}
+```
+
+## Creating Mocks
+
+FakeItEasy returns the fake as the interface type. TUnit.Mocks returns a `Mock` wrapper. For interfaces, the wrapper also implements the interface, so you can pass it directly to the code under test. Use `.Object` when you need the `T` instance explicitly.
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+IUserRepository sut = repository;
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+IUserRepository sut = repository; // implicit conversion
+IUserRepository same = repository.Object; // explicit instance
+```
+
+`T.Mock()` requires C# 14. You can also use the factory form `Mock.Of()`.
+
+Both libraries are loose by default. In TUnit.Mocks, a strict mock throws `MockStrictBehaviorException` for unconfigured calls.
+
+```csharp
+// FakeItEasy
+var repository = A.Fake(options => options.Strict());
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock(MockBehavior.Strict);
+```
+
+## Return Values
+
+Remove `A.CallTo(() => ...)` and call the member on the mock.
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+A.CallTo(() => repository.GetById(1)).Returns(new User(1, "Alice"));
+A.CallTo(() => repository.GetById(A.Ignored)).Returns(new User(0, "Anyone"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(1).Returns(new User(1, "Alice"));
+repository.GetById(Any()).Returns(new User(0, "Anyone"));
+```
+
+In both libraries, the most recently added matching setup wins.
+
+### Computed Return Values
+
+`ReturnsLazily` maps to `Returns` with a lambda. The parameters are the method's arguments.
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+A.CallTo(() => repository.GetById(A._)).ReturnsLazily((int id) => new User(id, "Generated"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(Any()).Returns((int id) => new User(id, "Generated"));
+```
+
+### Async Methods
+
+FakeItEasy accepts either a value or a task for async members. In TUnit.Mocks, `Returns` wraps the value in `Task` or `ValueTask` for you.
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+A.CallTo(() => repository.GetByIdAsync(1)).Returns(new User(1, "Alice"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetByIdAsync(1).Returns(new User(1, "Alice"));
+```
+
+To return a task you create yourself, such as one from a `TaskCompletionSource`, use `ReturnsAsync(task)`.
+
+### Sequences
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+A.CallTo(() => repository.GetById(1))
+ .Throws().Once()
+ .Then.ReturnsNextFromSequence(new User(1, "First"), new User(1, "Second"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(1)
+ .Throws()
+ .Then()
+ .ReturnsSequentially(new User(1, "First"), new User(1, "Second"));
+```
+
+When a FakeItEasy sequence ends, later calls fall back to the fake's default behavior. In TUnit.Mocks, the last behavior repeats. In this example, every call after the third call returns `"Second"`.
+
+FakeItEasy limits a behavior with `.Once()`, `.Twice()`, or `.NumberOfTimes(n)`. TUnit.Mocks has no repeat count: each `.Then()` step applies to one call. Without `.Then()`, chained behaviors apply to the same call.
+
+## Exceptions
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+A.CallTo(() => repository.GetById(-1)).Throws(new ArgumentOutOfRangeException("id"));
+A.CallTo(() => repository.GetByIdAsync(-1)).ThrowsAsync(new InvalidOperationException());
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(-1).Throws(new ArgumentOutOfRangeException("id"));
+repository.GetByIdAsync(-1).Throws();
+```
+
+TUnit.Mocks has no `ThrowsAsync`. For a method that returns `Task` or `ValueTask`, `Throws` returns a faulted task. It does not throw synchronously.
+
+## Callbacks and Void Methods
+
+`Invokes` maps to `Callback`. Declare the lambda parameter types to receive the method's arguments.
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+var saved = new List();
+A.CallTo(() => repository.Save(A._)).Invokes((User user) => saved.Add(user));
+A.CallTo(() => repository.Save(A.That.Matches(u => u.Id < 0))).Throws(new ArgumentException("Invalid id"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+var saved = new List();
+repository.Save(Any()).Callback((User user) => saved.Add(user));
+repository.Save(user => user.Id < 0).Throws(new ArgumentException("Invalid id"));
+```
+
+`DoesNothing()` has no direct equivalent. In strict mode, a void setup with no chained behavior allows the call: `repository.Save(Any());`.
+
+## Argument Constraints
+
+TUnit.Mocks imports its matchers globally. A raw value is an exact match, and a lambda is a predicate.
+
+| FakeItEasy | TUnit.Mocks |
+|---|---|
+| `A.Ignored` / `A._` | `Any()` or `Any()` |
+| `5` | `5` or `Is(5)` |
+| `A.That.Matches(x => x > 0)` | `x => x > 0` or `Is(x => x > 0)` |
+| `A.That.IsEqualTo(5)` | `5` or `Is(5)` |
+| `A.That.IsNull()` | `IsNull()` |
+| `A.That.IsNotNull()` | `IsNotNull()` |
+| `A.That.Not.IsEqualTo(0)` | `Not(Is(0))` |
+| `A>.That.Contains(5)` | `Contains, int>(5)` |
+| `A>.That.IsEmpty()` | `IsEmpty>()` |
+| `A>.That.IsSameSequenceAs(expected)` | `SequenceEquals, int>(expected)` |
+| `A.That.StartsWith("a")` | `s => s.StartsWith("a")` |
+| `.WithAnyArguments()` | `Any()` for each parameter, or `AnyArgs()` where generated |
+| `.WhenArgumentsMatch(args => ...)` | A lambda matcher on each parameter |
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+A.CallTo(() => repository.GetById(A.That.Matches(id => id > 100))).Returns(new User(101, "Admin"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(id => id > 100).Returns(new User(101, "Admin"));
+```
+
+To replace `.WithAnyArguments()`: pass `Any()` for each parameter. Some methods also get an `AnyArgs()` shortcut that replaces all of them. It is not generated for overloaded or generic methods, for methods with fewer than two matchable parameters, or for methods with `out`, `ref`, or ref-struct parameters. See [when the shortcut is generated](../../writing-tests/mocking/argument-matchers.md#anyargs--match-every-parameter-with-one-token).
+
+### Capturing Arguments
+
+FakeItEasy captures arguments with `Captured` or in `Invokes`. In TUnit.Mocks, every matcher records the values it matches. Store the matcher in a variable and read it after the code under test runs.
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+var savedUser = A.Captured();
+A.CallTo(() => repository.Save(savedUser._)).DoesNothing();
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+var userArg = Any();
+repository.Save(userArg);
+
+repository.Object.Save(new User(1, "Alice"));
+
+var saved = userArg.Values; // every matched value
+var last = userArg.Latest; // the most recent value
+```
+
+See [Argument Matchers](../../writing-tests/mocking/argument-matchers.md) for range, regex, and custom matchers.
+
+## Out and Ref Parameters
+
+FakeItEasy assigns `out` and `ref` values by position with `AssignsOutAndRefParameters`. TUnit.Mocks leaves `out` parameters out of the setup signature and generates a typed `SetsOut{ParameterName}` method for each one.
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+string ignored;
+A.CallTo(() => repository.TryGetName(1, out ignored))
+ .Returns(true)
+ .AssignsOutAndRefParameters("Alice");
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.TryGetName(1)
+ .Returns(true)
+ .SetsOutName("Alice");
+```
+
+`ref` parameters stay in the setup signature and use `SetsRef{ParameterName}`.
+
+## Properties
+
+FakeItEasy fakes behave like auto-properties: a value you set is returned by the getter. TUnit.Mocks properties return defaults until you configure them. Call `SetupAllProperties()` to get FakeItEasy's behavior.
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+A.CallTo(() => repository.ConnectionName).Returns("primary");
+A.CallToSet(() => repository.ConnectionName).To("replica").Throws();
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.ConnectionName.Returns("primary");
+repository.ConnectionName.Set("replica").Throws();
+
+// Opt in to auto-property behavior
+var tracked = IUserRepository.Mock();
+tracked.SetupAllProperties();
+tracked.Object.ConnectionName = "replica"; // the getter now returns "replica"
+```
+
+Setups made with `Returns` take precedence over values stored by `SetupAllProperties()`.
+
+## Verifying Calls
+
+Remove `A.CallTo(() => ...)`, call the member on the mock, and replace `MustHaveHappened` with `WasCalled`.
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+
+A.CallTo(() => repository.Save(A.That.Matches(u => u.Name == "Alice"))).MustHaveHappened();
+A.CallTo(() => repository.GetById(1)).MustHaveHappenedTwiceExactly();
+A.CallTo(() => repository.Save(A._)).MustNotHaveHappened();
+A.CallToSet(() => repository.ConnectionName).To("replica").MustHaveHappenedOnceExactly();
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+
+repository.Save(user => user.Name == "Alice").WasCalled();
+repository.GetById(1).WasCalled(Times.Exactly(2));
+repository.Save(Any()).WasNeverCalled();
+repository.ConnectionName.Set("replica").WasCalled(Times.Once);
+```
+
+| FakeItEasy | TUnit.Mocks |
+|---|---|
+| `MustHaveHappened()` | `WasCalled()` |
+| `MustHaveHappenedOnceExactly()` | `WasCalled(Times.Once)` |
+| `MustHaveHappenedTwiceExactly()` | `WasCalled(Times.Exactly(2))` |
+| `MustHaveHappenedANumberOfTimesMatching(n => n == 3)` | `WasCalled(Times.Exactly(3))` |
+| `MustHaveHappened(3, Times.OrMore)` | `WasCalled(Times.AtLeast(3))` |
+| `MustHaveHappened(3, Times.OrLess)` | `WasCalled(Times.AtMost(3))` |
+| `MustNotHaveHappened()` | `WasNeverCalled()` |
+
+`FakeItEasy.Times` and `TUnit.Mocks.Times` are different types. In a migrated file, `Times` refers to the TUnit.Mocks type.
+
+In a TUnit test, you can also await the check as an assertion. This needs the separate `TUnit.Mocks.Assertions` package (`dotnet add package TUnit.Mocks.Assertions`) and `using TUnit.Mocks.Assertions;`:
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+await Assert.That(repository.GetById(1)).WasCalled(Times.Once);
+```
+
+### Call Order
+
+FakeItEasy chains ordered checks with `.Then(...)`. TUnit.Mocks groups them in `Mock.VerifyInOrder`, which works across several mocks.
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+
+A.CallTo(() => repository.GetById(1)).MustHaveHappened()
+ .Then(A.CallTo(() => repository.Save(A._)).MustHaveHappened());
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+
+Mock.VerifyInOrder(() =>
+{
+ repository.GetById(1).WasCalled();
+ repository.Save(Any()).WasCalled();
+});
+```
+
+### Checks FakeItEasy Does Not Have
+
+TUnit.Mocks also provides `mock.VerifyAll()`, which fails if a setup was never used, and `mock.VerifyNoOtherCalls()`, which fails if a call was not verified. See [Verification](../../writing-tests/mocking/verification.md).
+
+## Events
+
+```csharp
+// FakeItEasy
+var repository = A.Fake();
+repository.UserSaved += Raise.With(new UserSavedEventArgs(new User(1, "Alice")));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.RaiseUserSaved(new UserSavedEventArgs(new User(1, "Alice")));
+```
+
+TUnit.Mocks generates a `Raise{EventName}` method for each event. To raise an event when a method is called, chain `.Raises{EventName}(...)` on a setup. See [Events](../../writing-tests/mocking/advanced.md#events).
+
+## Classes
+
+A FakeItEasy fake of a class does not call the base implementation unless you use `CallsBaseMethod()` or `options.CallsBaseMethods()`. A TUnit.Mocks class mock always calls the base implementation for unconfigured virtual members.
+
+```csharp
+// FakeItEasy
+var calculator = A.Fake(options => options.CallsBaseMethods());
+A.CallTo(() => calculator.Discount(A._)).Returns(5m);
+```
+
+```csharp
+// TUnit.Mocks
+var calculator = PriceCalculator.Mock();
+calculator.Discount(Any()).Returns(5m);
+
+decimal tax = calculator.Object.Tax(100m); // base implementation: 20
+```
+
+If a test depends on FakeItEasy's default behavior, configure each virtual member that the test calls. TUnit.Mocks can also configure `protected` virtual and abstract members with the same syntax as public members.
+
+## Other Features
+
+| FakeItEasy | TUnit.Mocks |
+|---|---|
+| Members that return interfaces return fakes | Loose mocks return auto-mocks; use `Mock.Get(instance)` to configure one |
+| `A.Dummy()` | No equivalent; use `T.Mock()` or a real value |
+| `A.Fake>()` | `Mock.OfDelegate>()` |
+| `A.CallTo(fake).Where(call => ...)` | No equivalent; configure each member |
+| `Fake.GetCalls(fake)` | `mock.Invocations` (a list of `CallRecord`) |
+| `Fake.ClearRecordedCalls(fake)` | `mock.Reset()`; it also clears setups and state |
+
+See [Advanced Features](../../writing-tests/mocking/advanced.md) for state machines, diagnostics, custom default values, and `MockRepository`.
+
+## Running Both Libraries Side by Side
+
+TUnit.Mocks adds these global usings to the project:
+
+- `TUnit.Mocks`
+- `TUnit.Mocks.Arguments`
+- `static TUnit.Mocks.Arguments.Arg`
+- `TUnit.Mocks.Generated`
+
+Most FakeItEasy names, such as `A`, `Fake`, and `Raise`, do not conflict with them. `Times` does: in a file that has `using FakeItEasy;`, `Times.OrMore` causes error `CS0104`. If you migrate one file at a time, use one of these fixes:
+
+- In files that still use FakeItEasy, add `using Times = FakeItEasy.Times;`.
+- Or set `disable` in the project and add the four usings above to each migrated file.
+
+When no file uses FakeItEasy, remove the `FakeItEasy` package reference. Also remove `FakeItEasy.Analyzer.CSharp` if the project uses it.
+
+## Native AOT
+
+FakeItEasy creates proxies at runtime with Castle DynamicProxy and `Reflection.Emit`, which Native AOT does not support. TUnit.Mocks generates mocks at compile time, so the migrated tests can run in a Native AOT or trimmed test application. See [AOT compatibility](../../writing-tests/aot.md).
+
+## Next Steps
+
+- [Setup and stubbing](../../writing-tests/mocking/setup.md)
+- [Verification](../../writing-tests/mocking/verification.md)
+- [Advanced features](../../writing-tests/mocking/advanced.md)
diff --git a/docs/docs/migration/mocking/moq.md b/docs/docs/migration/mocking/moq.md
new file mode 100644
index 00000000000..803ecdd6562
--- /dev/null
+++ b/docs/docs/migration/mocking/moq.md
@@ -0,0 +1,502 @@
+---
+sidebar_label: Moq
+---
+
+# Migrating from Moq to TUnit.Mocks
+
+TUnit.Mocks generates mocks at compile time instead of creating runtime proxies. Moq configures a mock with an expression, such as `mock.Setup(x => x.GetById(1))`. TUnit.Mocks generates a strongly typed member on the mock for each member of the mocked type, so you call `mock.GetById(1)` directly. The chained method decides the meaning: `.Returns()` configures a setup, and `.WasCalled()` verifies calls.
+
+TUnit.Mocks works with any test framework. You can migrate mocks before, after, or without migrating the tests to TUnit.
+
+## Before You Start
+
+1. Add the package:
+
+ ```bash
+ dotnet add package TUnit.Mocks
+ ```
+
+2. Set `14` (or `preview`) in the test project. TUnit.Mocks requires C# 14. Older versions report error `TM004`.
+3. Read [Running Both Libraries Side by Side](#running-both-libraries-side-by-side) if you migrate one file at a time. `Mock`, `Times`, `MockBehavior`, and `MockRepository` exist in both libraries.
+
+## Quick Reference
+
+| Moq | TUnit.Mocks |
+|---|---|
+| `new Mock()` | `IService.Mock()` |
+| `new Mock(MockBehavior.Strict)` | `IService.Mock(MockBehavior.Strict)` |
+| `new Mock(arg1, arg2) { CallBase = true }` | `MyClass.Mock(arg1, arg2)` |
+| `mock.Object` | `mock.Object`, or `mock` itself (converts implicitly) |
+| `mock.Setup(x => x.Method(1)).Returns(value)` | `mock.Method(1).Returns(value)` |
+| `mock.Setup(x => x.MethodAsync(1)).ReturnsAsync(value)` | `mock.MethodAsync(1).Returns(value)` |
+| `.Returns((int id) => ...)` | `.Returns((int id) => ...)` |
+| `.Throws()` / `.ThrowsAsync(ex)` | `.Throws()` / `.Throws(ex)` |
+| `.Callback(id => ...)` | `.Callback((int id) => ...)` |
+| `mock.SetupSequence(...)` | `.ReturnsSequentially(...)` or `.Then()` |
+| `mock.SetupGet(x => x.Prop).Returns(value)` | `mock.Prop.Returns(value)` |
+| `mock.SetupProperty(x => x.Prop)` / `mock.SetupAllProperties()` | `mock.SetupAllProperties()` |
+| `It.IsAny()` | `Any()` or `Any()` |
+| `It.Is(x => ...)` | `x => ...` or `Is(x => ...)` |
+| `It.IsIn(...)` / `It.IsNotIn(...)` | `IsIn(...)` / `IsNotIn(...)` |
+| `It.IsRegex(pattern)` | `Matches(pattern)` |
+| `It.IsNotNull()` | `IsNotNull()` |
+| `mock.Verify(x => x.Method(1), Times.Once())` | `mock.Method(1).WasCalled(Times.Once)` |
+| `mock.Verify(x => x.Method(1), Times.Never())` | `mock.Method(1).WasNeverCalled()` |
+| `mock.VerifySet(x => x.Prop = value)` | `mock.Prop.Set(value).WasCalled()` |
+| `mock.Verify()` (`.Verifiable()` setups) | `.WasCalled()` on each of those calls |
+| `mock.VerifyAll()` | `mock.VerifyAll()` (does not mark calls as verified for `VerifyNoOtherCalls()`) |
+| `mock.VerifyNoOtherCalls()` | `mock.VerifyNoOtherCalls()` |
+| `mock.Raise(x => x.Event += null, args)` | `mock.Raise{EventName}(args)` |
+| `mock.As()` | `Mock.Of()` |
+| `Mock.Get(instance)` | `Mock.Get(instance)` |
+| `mock.Invocations` | `mock.Invocations` |
+| `mock.Reset()` | `mock.Reset()` |
+| `new MockRepository(MockBehavior.Strict)` | `new MockRepository(MockBehavior.Strict)` |
+
+
+
+## Example Types
+
+The examples on this page use these types:
+
+```csharp
+public record User(int Id, string Name);
+
+public sealed class UserSavedEventArgs(User user) : EventArgs
+{
+ public User User { get; } = user;
+}
+
+public interface IUserRepository
+{
+ User? GetById(int id);
+ Task GetByIdAsync(int id);
+ void Save(User user);
+ bool TryGetName(int id, out string name);
+ string ConnectionName { get; set; }
+ event EventHandler? UserSaved;
+}
+
+public abstract class PriceCalculator
+{
+ public virtual decimal Tax(decimal amount) => amount * 0.2m;
+ public abstract decimal Discount(decimal amount);
+}
+```
+
+## Creating Mocks
+
+Both libraries return a `Mock` wrapper. For interfaces, the TUnit.Mocks wrapper also implements the interface, so you can pass the mock directly to the code under test. `.Object` still works.
+
+```csharp
+// Moq
+var repository = new Mock();
+IUserRepository sut = repository.Object;
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+IUserRepository sut = repository; // implicit conversion
+IUserRepository same = repository.Object; // explicit instance
+```
+
+`T.Mock()` requires C# 14. You can also use the factory form `Mock.Of()`. Moq's `Mock.Of()` returns the mocked object, but TUnit.Mocks' `Mock.Of()` returns the `Mock` wrapper.
+
+Both libraries are loose by default. `MockBehavior.Strict` makes unconfigured calls throw. TUnit.Mocks throws `MockStrictBehaviorException`.
+
+```csharp
+// Moq
+var repository = new Mock(MockBehavior.Strict);
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock(MockBehavior.Strict);
+```
+
+## Return Values
+
+Remove the `Setup(x => ...)` expression and call the member on the mock.
+
+```csharp
+// Moq
+var repository = new Mock();
+repository.Setup(x => x.GetById(1)).Returns(new User(1, "Alice"));
+repository.Setup(x => x.GetById(It.IsAny())).Returns(new User(0, "Anyone"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(1).Returns(new User(1, "Alice"));
+repository.GetById(Any()).Returns(new User(0, "Anyone"));
+```
+
+In both libraries, the most recently added matching setup wins.
+
+### Computed Return Values
+
+The lambda syntax is the same. The parameters are the method's arguments.
+
+```csharp
+// Moq
+var repository = new Mock();
+repository.Setup(x => x.GetById(It.IsAny())).Returns((int id) => new User(id, "Generated"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(Any()).Returns((int id) => new User(id, "Generated"));
+```
+
+### Async Methods
+
+Moq uses `ReturnsAsync`. In TUnit.Mocks, `Returns` wraps the value in `Task` or `ValueTask` for you.
+
+```csharp
+// Moq
+var repository = new Mock();
+repository.Setup(x => x.GetByIdAsync(1)).ReturnsAsync(new User(1, "Alice"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetByIdAsync(1).Returns(new User(1, "Alice"));
+```
+
+TUnit.Mocks also has `ReturnsAsync`, but it takes a task, for example one from a `TaskCompletionSource`. Use it when the test controls when the task completes.
+
+### Sequences
+
+`SetupSequence` maps to `ReturnsSequentially` for values and to `.Then()` for mixed behavior.
+
+```csharp
+// Moq
+var repository = new Mock();
+repository.SetupSequence(x => x.GetById(1))
+ .Throws()
+ .Returns(new User(1, "First"))
+ .Returns(new User(1, "Second"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(1)
+ .Throws()
+ .Then()
+ .ReturnsSequentially(new User(1, "First"), new User(1, "Second"));
+```
+
+When a Moq sequence ends, later calls return the default value. In TUnit.Mocks, the last behavior repeats. In this example, every call after the third call returns `"Second"`.
+
+Without `.Then()`, chained behaviors apply to the same call. For example, `.Returns(a).Returns(b)` always returns `b`.
+
+## Exceptions
+
+```csharp
+// Moq
+var repository = new Mock();
+repository.Setup(x => x.GetById(-1)).Throws(new ArgumentOutOfRangeException("id"));
+repository.Setup(x => x.GetByIdAsync(-1)).ThrowsAsync(new InvalidOperationException());
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(-1).Throws(new ArgumentOutOfRangeException("id"));
+repository.GetByIdAsync(-1).Throws();
+```
+
+TUnit.Mocks has no `ThrowsAsync`. For a method that returns `Task` or `ValueTask`, `Throws` returns a faulted task. It does not throw synchronously.
+
+## Callbacks and Void Methods
+
+Moq passes arguments to `Callback(...)` through generic type arguments. TUnit.Mocks generates typed overloads, so declare the lambda parameter types.
+
+```csharp
+// Moq
+var repository = new Mock();
+var saved = new List();
+repository.Setup(x => x.Save(It.IsAny())).Callback(user => saved.Add(user));
+repository.Setup(x => x.Save(It.Is(u => u.Id < 0))).Throws(new ArgumentException("Invalid id"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+var saved = new List();
+repository.Save(Any()).Callback((User user) => saved.Add(user));
+repository.Save(user => user.Id < 0).Throws(new ArgumentException("Invalid id"));
+```
+
+In strict mode, a void setup with no chained behavior allows the call: `repository.Save(Any());`. It replaces `Setup(x => x.Save(It.IsAny()))` with no `Callback`.
+
+## Argument Matchers
+
+TUnit.Mocks imports its matchers globally, so you do not need a prefix like `It.`. A raw value is an exact match, and a lambda is a predicate.
+
+| Moq | TUnit.Mocks |
+|---|---|
+| `It.IsAny()` | `Any()` or `Any()` |
+| `5` | `5` or `Is(5)` |
+| `It.Is(x => x > 0)` | `x => x > 0` or `Is(x => x > 0)` |
+| `It.IsIn(1, 2, 3)` | `IsIn(1, 2, 3)` |
+| `It.IsNotIn(1, 2, 3)` | `IsNotIn(1, 2, 3)` |
+| `It.IsInRange(1, 10, Range.Inclusive)` | `IsInRange(1, 10)` (always inclusive) |
+| `It.IsRegex(pattern)` | `Matches(pattern)` |
+| `It.IsNotNull()` | `IsNotNull()` |
+| `It.Is(x => x == null)` | `IsNull()` |
+| `It.Ref.IsAny` | `Any()` |
+| `Capture.In(list)` | Store an `Any()` matcher and read `.Values` |
+
+```csharp
+// Moq
+var repository = new Mock();
+repository.Setup(x => x.GetById(It.Is(id => id > 100))).Returns(new User(101, "Admin"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(id => id > 100).Returns(new User(101, "Admin"));
+```
+
+### Capturing Arguments
+
+Every TUnit.Mocks matcher records the values it matches. Store the matcher in a variable and read it after the code under test runs.
+
+```csharp
+// Moq
+var repository = new Mock();
+var saved = new List();
+repository.Setup(x => x.Save(Capture.In(saved)));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+var userArg = Any();
+repository.Save(userArg);
+
+repository.Object.Save(new User(1, "Alice"));
+
+var saved = userArg.Values; // every matched value
+var last = userArg.Latest; // the most recent value
+```
+
+See [Argument Matchers](../../writing-tests/mocking/argument-matchers.md) for collection, range, and custom matchers.
+
+## Out and Ref Parameters
+
+Moq takes the `out` value from a variable in the setup expression. TUnit.Mocks leaves `out` parameters out of the setup signature and generates a `SetsOut{ParameterName}` method for each one.
+
+```csharp
+// Moq
+var repository = new Mock();
+var name = "Alice";
+repository.Setup(x => x.TryGetName(1, out name)).Returns(true);
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.TryGetName(1)
+ .Returns(true)
+ .SetsOutName("Alice");
+```
+
+`ref` parameters stay in the setup signature and use `SetsRef{ParameterName}`.
+
+## Properties
+
+TUnit.Mocks exposes each property on the mock. The getter is the default target, and `.Setter` or `.Set(value)` targets the setter.
+
+```csharp
+// Moq
+var repository = new Mock();
+repository.SetupGet(x => x.ConnectionName).Returns("primary");
+repository.SetupSet(x => x.ConnectionName = "replica").Throws();
+repository.SetupAllProperties();
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.ConnectionName.Returns("primary");
+repository.ConnectionName.Set("replica").Throws();
+repository.SetupAllProperties();
+```
+
+`SetupAllProperties()` makes every property store and return values. TUnit.Mocks has no per-property `SetupProperty`; use `SetupAllProperties()`, or configure the getter with `Returns`. Setups made with `Returns` take precedence over stored values.
+
+## Verifying Calls
+
+Remove the `Verify(x => ...)` expression, call the member on the mock, and chain `WasCalled` or `WasNeverCalled`. In TUnit.Mocks, `Times` members such as `Times.Once` are properties, not methods.
+
+```csharp
+// Moq
+var repository = new Mock();
+
+repository.Verify(x => x.Save(It.Is(u => u.Name == "Alice")));
+repository.Verify(x => x.GetById(1), Times.Exactly(2));
+repository.Verify(x => x.Save(It.IsAny()), Times.Never());
+repository.VerifySet(x => x.ConnectionName = "replica", Times.Once());
+repository.VerifyGet(x => x.ConnectionName, Times.AtLeastOnce());
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+
+repository.Save(user => user.Name == "Alice").WasCalled();
+repository.GetById(1).WasCalled(Times.Exactly(2));
+repository.Save(Any()).WasNeverCalled();
+repository.ConnectionName.Set("replica").WasCalled(Times.Once);
+repository.ConnectionName.WasCalled(Times.AtLeastOnce);
+```
+
+| Moq | TUnit.Mocks |
+|---|---|
+| `Times.Once()` | `Times.Once` |
+| `Times.Never()` | `Times.Never` or `.WasNeverCalled()` |
+| `Times.AtLeastOnce()` | `Times.AtLeastOnce` or `.WasCalled()` |
+| `Times.Exactly(n)` | `Times.Exactly(n)` |
+| `Times.AtLeast(n)` / `Times.AtMost(n)` | `Times.AtLeast(n)` / `Times.AtMost(n)` |
+| `Times.Between(min, max, Range.Inclusive)` | `Times.Between(min, max)` (always inclusive) |
+
+Both libraries accept a failure message: `.WasCalled(Times.Once, "Save should run once")`.
+
+In a TUnit test, you can also await the check as an assertion. This needs the separate `TUnit.Mocks.Assertions` package (`dotnet add package TUnit.Mocks.Assertions`) and `using TUnit.Mocks.Assertions;`:
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+await Assert.That(repository.GetById(1)).WasCalled(Times.Once);
+```
+
+### Verifiable Setups and VerifyAll
+
+Moq's `mock.Verify()` checks only setups marked `.Verifiable()`. TUnit.Mocks has no `Verifiable()`, so verify each of those calls with `WasCalled()`. This also marks the call as verified for `VerifyNoOtherCalls()`. Do not replace `Verify()` with `VerifyAll()`: `VerifyAll()` also fails for unused setups that were not verifiable, and it does not mark calls as verified.
+
+```csharp
+// Moq
+var repository = new Mock();
+repository.Setup(x => x.GetById(1)).Returns(new User(1, "Alice")).Verifiable();
+
+repository.Object.GetById(1); // the code under test
+
+repository.Verify();
+repository.VerifyNoOtherCalls();
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(1).Returns(new User(1, "Alice"));
+
+repository.Object.GetById(1); // the code under test
+
+repository.GetById(1).WasCalled();
+repository.VerifyNoOtherCalls();
+```
+
+### Call Order
+
+Moq checks order with `MockSequence` and `InSequence`, which configure strict setups. TUnit.Mocks checks order after the code runs, across one or more mocks:
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+
+Mock.VerifyInOrder(() =>
+{
+ repository.GetById(1).WasCalled();
+ repository.Save(Any()).WasCalled();
+});
+```
+
+## Events
+
+```csharp
+// Moq
+var repository = new Mock();
+repository.Raise(x => x.UserSaved += null, new UserSavedEventArgs(new User(1, "Alice")));
+repository.Setup(x => x.Save(It.IsAny()))
+ .Raises(x => x.UserSaved += null, new UserSavedEventArgs(new User(2, "Bob")));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.RaiseUserSaved(new UserSavedEventArgs(new User(1, "Alice")));
+repository.Save(Any())
+ .RaisesUserSaved(new UserSavedEventArgs(new User(2, "Bob")));
+```
+
+TUnit.Mocks generates a `Raise{EventName}` method and a `.Raises{EventName}` setup method for each event. See [Events](../../writing-tests/mocking/advanced.md#events).
+
+## Classes and Protected Members
+
+Moq calls the base implementation only when `CallBase = true`. A TUnit.Mocks class mock always calls the base implementation for unconfigured virtual members. Pass constructor arguments as typed parameters.
+
+```csharp
+// Moq
+var calculator = new Mock { CallBase = true };
+calculator.Setup(x => x.Discount(It.IsAny())).Returns(5m);
+```
+
+```csharp
+// TUnit.Mocks
+var calculator = PriceCalculator.Mock();
+calculator.Discount(Any()).Returns(5m);
+
+decimal tax = calculator.Object.Tax(100m); // base implementation: 20
+```
+
+If a test depends on Moq's default `CallBase = false`, configure each virtual member that the test calls.
+
+Moq configures `protected` members with `mock.Protected().Setup("Name", ...)` and string names. TUnit.Mocks generates typed members for `protected` virtual and abstract members, so you configure and verify them like public members.
+
+## Other Features
+
+| Moq | TUnit.Mocks |
+|---|---|
+| `DefaultValue.Mock` | Default in loose mode: members that return interfaces return auto-mocks |
+| `mock.DefaultValueProvider = ...` | `mock.DefaultValueProvider = ...` (implement `IDefaultValueProvider`) |
+| `mock.As()` | `Mock.Of()` (up to four types) |
+| `Mock.Of(x => x.Prop == value)` | `IService.Mock()` and then `mock.Prop.Returns(value)` |
+| `new Mock>()` | `Mock.OfDelegate>()` |
+| `mock.Invocations.Clear()` | `mock.Reset()` (also clears setups and state) |
+| `Mock.Get(instance)` | `Mock.Get(instance)` |
+
+To wrap an existing instance of a non-sealed class and override only some of its virtual members, use `Mock.Wrap(instance)`. `Mock.Wrap` does not support interfaces. See [Advanced Features](../../writing-tests/mocking/advanced.md) for state machines, diagnostics, and `MockRepository`.
+
+## Running Both Libraries Side by Side
+
+TUnit.Mocks adds these global usings to the project:
+
+- `TUnit.Mocks`
+- `TUnit.Mocks.Arguments`
+- `static TUnit.Mocks.Arguments.Arg`
+- `TUnit.Mocks.Generated`
+
+In a file that also has `using Moq;`, the names `Mock`, `Mock`, `MockBehavior`, `MockRepository`, and `Times` each refer to two types. That causes error `CS0104`. If you migrate one file at a time, use one of these fixes:
+
+- Set `disable` in the project and add the four usings above to each migrated file. Files that still use Moq then compile unchanged.
+- Or, in files that still use Moq, move `using Moq;` inside the file's namespace declaration. A using directive inside a namespace takes precedence over global usings.
+
+When no file uses Moq, remove the `Moq` package reference.
+
+## Native AOT
+
+Moq creates proxies at runtime with Castle DynamicProxy and `Reflection.Emit`, which Native AOT does not support. TUnit.Mocks generates mocks at compile time, so the migrated tests can run in a Native AOT or trimmed test application. See [AOT compatibility](../../writing-tests/aot.md).
+
+## Next Steps
+
+- [Setup and stubbing](../../writing-tests/mocking/setup.md)
+- [Verification](../../writing-tests/mocking/verification.md)
+- [Advanced features](../../writing-tests/mocking/advanced.md)
diff --git a/docs/docs/migration/mocking/nsubstitute.md b/docs/docs/migration/mocking/nsubstitute.md
new file mode 100644
index 00000000000..44884f424d3
--- /dev/null
+++ b/docs/docs/migration/mocking/nsubstitute.md
@@ -0,0 +1,484 @@
+---
+sidebar_label: NSubstitute
+---
+
+# Migrating from NSubstitute to TUnit.Mocks
+
+TUnit.Mocks generates mocks at compile time instead of creating runtime proxies. The API is close to NSubstitute's: you call the member you want to configure and chain `.Returns()`. The main change is where the call happens. NSubstitute configures calls on the substitute itself. TUnit.Mocks configures them on a `Mock` wrapper, which is also usable as the mocked interface.
+
+TUnit.Mocks works with any test framework. You can migrate mocks before, after, or without migrating the tests to TUnit.
+
+## Before You Start
+
+1. Add the package:
+
+ ```bash
+ dotnet add package TUnit.Mocks
+ ```
+
+2. Set `14` (or `preview`) in the test project. TUnit.Mocks requires C# 14. Older versions report error `TM004`.
+3. Read [Running Both Libraries Side by Side](#running-both-libraries-side-by-side) if you migrate one file at a time. TUnit.Mocks adds global usings, and its `Arg` type conflicts with `NSubstitute.Arg`.
+
+## Quick Reference
+
+| NSubstitute | TUnit.Mocks |
+|---|---|
+| `Substitute.For()` | `IService.Mock()` |
+| `Substitute.For()` | `Mock.Of()` |
+| `Substitute.ForPartsOf()` | `MyClass.Mock()` (unconfigured virtual members call the base implementation) |
+| `Substitute.For>()` | `Mock.OfDelegate>()` |
+| Substitute passed to the code under test | `mock` (converts implicitly) or `mock.Object` |
+| `sub.Method(1).Returns(value)` | `mock.Method(1).Returns(value)` |
+| `sub.Method(1).Returns(a, b, c)` | `mock.Method(1).ReturnsSequentially(a, b, c)` |
+| `sub.Method(1).Returns(call => ...)` | `mock.Method(1).Returns((int id) => ...)` |
+| `sub.MethodAsync(1).Returns(value)` | `mock.MethodAsync(1).Returns(value)` |
+| `sub.Method(1).ReturnsForAnyArgs(value)` | `mock.Method(Any()).Returns(value)` (`Any()` for each parameter; see [Ignoring Arguments](#ignoring-arguments)) |
+| `sub.Method(1).Throws(ex)` / `.ThrowsAsync(ex)` | `mock.Method(1).Throws(ex)` |
+| `sub.When(x => x.Void()).Do(call => ...)` | `mock.Void().Callback(() => ...)` |
+| `Arg.Any()` | `Any()` or `Any()` |
+| `Arg.Is(value)` | `value` or `Is(value)` |
+| `Arg.Is(x => ...)` | `x => ...` or `Is(x => ...)` |
+| `Arg.Do(x => list.Add(x))` | `var arg = Any();` then read `arg.Values` |
+| `sub.Received().Method(1)` | `mock.Method(1).WasCalled()` |
+| `sub.Received(3).Method(1)` | `mock.Method(1).WasCalled(Times.Exactly(3))` |
+| `sub.DidNotReceive().Method(1)` | `mock.Method(1).WasNeverCalled()` |
+| `sub.ReceivedWithAnyArgs().Method(default)` | `mock.Method(Any()).WasCalled()` (`Any()` for each parameter; see [Ignoring Arguments](#ignoring-arguments)) |
+| `Received.InOrder(() => { ... })` | `Mock.VerifyInOrder(() => { ... })` |
+| `sub.ReceivedCalls()` | `mock.Invocations` |
+| `sub.ClearReceivedCalls()` | `mock.Reset()` (also clears setups) |
+| `sub.Event += Raise.EventWith(args)` | `mock.Raise{EventName}(args)` |
+| Auto-properties on substitutes | `mock.SetupAllProperties()` |
+
+
+
+## Example Types
+
+The examples on this page use these types:
+
+```csharp
+public record User(int Id, string Name);
+
+public sealed class UserSavedEventArgs(User user) : EventArgs
+{
+ public User User { get; } = user;
+}
+
+public interface IUserRepository
+{
+ User? GetById(int id);
+ Task GetByIdAsync(int id);
+ void Save(User user);
+ bool TryGetName(int id, out string name);
+ string ConnectionName { get; set; }
+ event EventHandler? UserSaved;
+}
+
+public abstract class PriceCalculator
+{
+ public virtual decimal Tax(decimal amount) => amount * 0.2m;
+ public abstract decimal Discount(decimal amount);
+}
+```
+
+## Creating Mocks
+
+NSubstitute returns the substitute as the interface type. TUnit.Mocks returns a `Mock` wrapper. For interfaces, the wrapper also implements the interface, so you can pass it directly to the code under test. Use `.Object` when you need the `T` instance explicitly.
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+IUserRepository sut = repository;
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+IUserRepository sut = repository; // implicit conversion
+IUserRepository same = repository.Object; // explicit instance
+```
+
+`T.Mock()` requires C# 14. You can also use the factory form `Mock.Of()`.
+
+NSubstitute has no strict mode. TUnit.Mocks is loose by default, like NSubstitute. Pass `MockBehavior.Strict` to make unconfigured calls throw `MockStrictBehaviorException`:
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock(MockBehavior.Strict);
+```
+
+## Return Values
+
+The basic setup is almost identical. The call goes to the mock wrapper instead of the substitute.
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+repository.GetById(1).Returns(new User(1, "Alice"));
+repository.GetById(Arg.Any()).Returns(new User(0, "Anyone"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(1).Returns(new User(1, "Alice"));
+repository.GetById(Any()).Returns(new User(0, "Anyone"));
+```
+
+In both libraries, the most recently added matching setup wins.
+
+### Computed Return Values
+
+NSubstitute passes a `CallInfo` and you read arguments by type or position. TUnit.Mocks passes the method's arguments as typed lambda parameters.
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+repository.GetById(Arg.Any()).Returns(call => new User(call.Arg(), "Generated"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(Any()).Returns((int id) => new User(id, "Generated"));
+```
+
+### Sequential Return Values
+
+NSubstitute's multi-value `Returns(a, b, c)` maps to `ReturnsSequentially`. In both libraries, the last value repeats after the sequence ends.
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+repository.GetById(1).Returns(new User(1, "First"), new User(1, "Second"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(1).ReturnsSequentially(new User(1, "First"), new User(1, "Second"));
+```
+
+To mix return values and exceptions across calls, chain `.Then()`:
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(1)
+ .Throws()
+ .Then()
+ .Returns(new User(1, "Alice"));
+```
+
+### Async Methods
+
+Both libraries accept the unwrapped value for `Task` and `ValueTask` members. TUnit.Mocks wraps it in the task for you, so async setups usually need no change.
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+repository.GetByIdAsync(1).Returns(new User(1, "Alice"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetByIdAsync(1).Returns(new User(1, "Alice"));
+```
+
+To return a task you create yourself, such as one from a `TaskCompletionSource`, use `ReturnsAsync(task)`.
+
+### Ignoring Arguments
+
+`ReturnsForAnyArgs` and `ReceivedWithAnyArgs` have no direct equivalent. Pass `Any()` for each parameter. Some methods also get an `AnyArgs()` shortcut that replaces all of them. It is not generated for overloaded or generic methods, for methods with fewer than two matchable parameters, or for methods with `out`, `ref`, or ref-struct parameters. See [when the shortcut is generated](../../writing-tests/mocking/argument-matchers.md#anyargs--match-every-parameter-with-one-token).
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+repository.GetById(default).ReturnsForAnyArgs(new User(0, "Anyone"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(Any()).Returns(new User(0, "Anyone"));
+```
+
+## Exceptions
+
+NSubstitute uses `Throws` and `ThrowsAsync` from `NSubstitute.ExceptionExtensions`. TUnit.Mocks uses `Throws` for both. For a method that returns `Task` or `ValueTask`, the mock returns a faulted task. It does not throw synchronously.
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+repository.GetById(-1).Throws(new ArgumentOutOfRangeException("id"));
+repository.GetByIdAsync(-1).ThrowsAsync(new InvalidOperationException());
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(-1).Throws(new ArgumentOutOfRangeException("id"));
+repository.GetByIdAsync(-1).Throws();
+```
+
+## Callbacks and Void Methods
+
+NSubstitute configures void members with `When(...).Do(...)`. In TUnit.Mocks, call the void member on the mock and chain `Callback` or `Throws`. Typed callbacks receive the method's arguments.
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+var saved = new List();
+repository.When(x => x.Save(Arg.Any())).Do(call => saved.Add(call.Arg()));
+repository.When(x => x.Save(Arg.Is(u => u.Id < 0))).Do(_ => throw new ArgumentException("Invalid id"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+var saved = new List();
+repository.Save(Any()).Callback((User user) => saved.Add(user));
+repository.Save(user => user.Id < 0).Throws(new ArgumentException("Invalid id"));
+```
+
+`Callback` and `Throws` work on methods with return values too. For example, `.Callback(...).Returns(...)` runs the callback and returns the value.
+
+## Argument Matchers
+
+TUnit.Mocks imports its matchers globally, so you do not need the `Arg.` prefix. A raw value is an exact match, and a lambda is a predicate.
+
+| NSubstitute | TUnit.Mocks |
+|---|---|
+| `Arg.Any()` | `Any()` or `Any()` |
+| `Arg.Is(5)` | `5` or `Is(5)` |
+| `Arg.Is(x => x > 0)` | `x => x > 0` or `Is(x => x > 0)` |
+| `Arg.Is(x => x == null)` | `IsNull()` |
+| `Arg.Is(x => x != null)` | `IsNotNull()` |
+| `Arg.Is(x => Regex.IsMatch(x, pattern))` | `Matches(pattern)` |
+| `Arg.Do(x => list.Add(x))` | Store an `Any()` matcher and read `.Values` or `.Latest` |
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+repository.GetById(Arg.Is(id => id > 100)).Returns(new User(101, "Admin"));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.GetById(id => id > 100).Returns(new User(101, "Admin"));
+```
+
+### Capturing Arguments
+
+NSubstitute captures arguments with `Arg.Do`. In TUnit.Mocks, every matcher records the values it matches. Store the matcher in a variable and read it after the code under test runs.
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+var saved = new List();
+repository.Save(Arg.Do(user => saved.Add(user)));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+var userArg = Any();
+repository.Save(userArg);
+
+repository.Object.Save(new User(1, "Alice"));
+
+var saved = userArg.Values; // every matched value
+var last = userArg.Latest; // the most recent value
+```
+
+See [Argument Matchers](../../writing-tests/mocking/argument-matchers.md) for collection, range, and custom matchers.
+
+## Out and Ref Parameters
+
+NSubstitute sets `out` values through the `CallInfo` argument array. TUnit.Mocks leaves `out` parameters out of the setup signature and generates a `SetsOut{ParameterName}` method for each one.
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+repository.TryGetName(1, out _).Returns(call =>
+{
+ call[1] = "Alice";
+ return true;
+});
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.TryGetName(1)
+ .Returns(true)
+ .SetsOutName("Alice");
+```
+
+`ref` parameters stay in the setup signature and use `SetsRef{ParameterName}`.
+
+## Properties
+
+NSubstitute substitutes behave like auto-properties: a value you set is returned by the getter. TUnit.Mocks properties return defaults until you configure them. Call `SetupAllProperties()` to get NSubstitute's behavior.
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+repository.ConnectionName.Returns("primary");
+
+repository.ConnectionName = "replica"; // the getter now returns "replica"
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.ConnectionName.Returns("primary");
+
+// Opt in to auto-property behavior
+var tracked = IUserRepository.Mock();
+tracked.SetupAllProperties();
+tracked.Object.ConnectionName = "replica"; // the getter now returns "replica"
+```
+
+Setups made with `Returns` take precedence over values stored by `SetupAllProperties()`.
+
+## Verifying Calls
+
+NSubstitute checks calls with `Received()` before the member. TUnit.Mocks calls the member on the mock and then chains `WasCalled()` or `WasNeverCalled()`. Both throw when the check fails.
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+
+repository.Received().Save(Arg.Is(u => u.Name == "Alice"));
+repository.Received(2).GetById(1);
+repository.DidNotReceive().Save(Arg.Is(u => u.Id < 0));
+repository.ReceivedWithAnyArgs().GetById(default);
+repository.Received().ConnectionName = "replica";
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+
+repository.Save(user => user.Name == "Alice").WasCalled();
+repository.GetById(1).WasCalled(Times.Exactly(2));
+repository.Save(user => user.Id < 0).WasNeverCalled();
+repository.GetById(Any()).WasCalled();
+repository.ConnectionName.Set("replica").WasCalled();
+```
+
+`WasCalled()` without arguments means at least once, like `Received()`. The `Times` class also has `Once`, `Never`, `AtLeastOnce`, `AtLeast(n)`, `AtMost(n)`, and `Between(min, max)`.
+
+In a TUnit test, you can also await the check as an assertion. This needs the separate `TUnit.Mocks.Assertions` package (`dotnet add package TUnit.Mocks.Assertions`) and `using TUnit.Mocks.Assertions;`:
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+await Assert.That(repository.GetById(1)).WasCalled(Times.Once);
+```
+
+### Call Order
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+
+Received.InOrder(() =>
+{
+ repository.GetById(1);
+ repository.Save(Arg.Any());
+});
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+
+Mock.VerifyInOrder(() =>
+{
+ repository.GetById(1).WasCalled();
+ repository.Save(Any()).WasCalled();
+});
+```
+
+`Mock.VerifyInOrder` works across several mocks.
+
+### Checks NSubstitute Does Not Have
+
+TUnit.Mocks also provides `mock.VerifyAll()`, which fails if a setup was never used, and `mock.VerifyNoOtherCalls()`, which fails if a call was not verified. See [Verification](../../writing-tests/mocking/verification.md).
+
+## Events
+
+```csharp
+// NSubstitute
+var repository = Substitute.For();
+repository.UserSaved += Raise.EventWith(new UserSavedEventArgs(new User(1, "Alice")));
+```
+
+```csharp
+// TUnit.Mocks
+var repository = IUserRepository.Mock();
+repository.RaiseUserSaved(new UserSavedEventArgs(new User(1, "Alice")));
+```
+
+TUnit.Mocks generates a `Raise{EventName}` method for each event. To raise an event when a method is called, chain `.Raises{EventName}(...)` on a setup. See [Events](../../writing-tests/mocking/advanced.md#events).
+
+## Partial Mocks and Classes
+
+`Substitute.ForPartsOf()` calls the real implementation for members you do not configure. A TUnit.Mocks class mock does the same for every unconfigured virtual member, so `T.Mock()` replaces `ForPartsOf()`.
+
+```csharp
+// NSubstitute
+var calculator = Substitute.ForPartsOf();
+calculator.Discount(Arg.Any()).Returns(5m);
+```
+
+```csharp
+// TUnit.Mocks
+var calculator = PriceCalculator.Mock();
+calculator.Discount(Any()).Returns(5m);
+
+decimal tax = calculator.Object.Tax(100m); // base implementation: 20
+```
+
+This is different from `Substitute.For()`, which does not call the base implementation of virtual members. If you depend on that, configure each member you call. Pass constructor arguments as typed parameters: `MyService.Mock("connection", 42)`.
+
+TUnit.Mocks can also configure `protected` virtual and abstract members with the same syntax as public members. To wrap an existing instance of a non-sealed class and override only some of its virtual members, use `Mock.Wrap(instance)`. `Mock.Wrap` does not support interfaces.
+
+## Other Features
+
+| NSubstitute | TUnit.Mocks |
+|---|---|
+| Recursive mocks (interface members return substitutes) | Loose mocks return auto-mocks; use `Mock.Get(instance)` to configure one |
+| `sub.ReceivedCalls()` | `mock.Invocations` (a list of `CallRecord`) |
+| `sub.ClearReceivedCalls()` | `mock.Reset()`; it also clears setups and state |
+| `Substitute.For()` | `Mock.Of()` (up to four types) |
+| `.Configure()` before setting up a partial | Not needed; setup never calls the real member |
+
+## Running Both Libraries Side by Side
+
+TUnit.Mocks adds these global usings to the project:
+
+- `TUnit.Mocks`
+- `TUnit.Mocks.Arguments`
+- `static TUnit.Mocks.Arguments.Arg`
+- `TUnit.Mocks.Generated`
+
+In a file that also has `using NSubstitute;`, the name `Arg` refers to two types. That causes error `CS0104`. If you migrate one file at a time, use one of these fixes:
+
+- In files that still use NSubstitute, add `using Arg = NSubstitute.Arg;`.
+- Or set `disable` in the project and add the four usings above to each migrated file.
+
+When no file uses NSubstitute, remove the `NSubstitute` package reference. Also remove `NSubstitute.Analyzers` if the project uses it.
+
+## Native AOT
+
+NSubstitute creates proxies at runtime with `Reflection.Emit`, which Native AOT does not support. TUnit.Mocks generates mocks at compile time, so the migrated tests can run in a Native AOT or trimmed test application. See [AOT compatibility](../../writing-tests/aot.md).
+
+## Next Steps
+
+- [Setup and stubbing](../../writing-tests/mocking/setup.md)
+- [Verification](../../writing-tests/mocking/verification.md)
+- [Advanced features](../../writing-tests/mocking/advanced.md): state machines, auto-mocking, diagnostics, and `MockRepository`
diff --git a/docs/docs/writing-tests/mocking/index.md b/docs/docs/writing-tests/mocking/index.md
index ab9ce1cd5fe..c88f8471b1f 100644
--- a/docs/docs/writing-tests/mocking/index.md
+++ b/docs/docs/writing-tests/mocking/index.md
@@ -210,3 +210,4 @@ See [Argument Matchers](argument-matchers) for the full API.
- [Advanced Features](advanced) — state machines, events, auto-mocking, diagnostics, and more
- [HTTP Mocking](http) — mock `HttpClient` with `MockHttpHandler`
- [Logging](logging) — capture and verify `ILogger` calls with `MockLogger`
+- Migrating from another library — [Moq](../../migration/mocking/moq.md), [NSubstitute](../../migration/mocking/nsubstitute.md), or [FakeItEasy](../../migration/mocking/fakeiteasy.md)
diff --git a/docs/sidebars.ts b/docs/sidebars.ts
index 67f2f9094bb..03307acf5cd 100644
--- a/docs/sidebars.ts
+++ b/docs/sidebars.ts
@@ -227,6 +227,16 @@ const sidebars: SidebarsConfig = {
'migration/xunit',
'migration/nunit',
'migration/mstest',
+ {
+ type: 'category',
+ label: 'Mocking Libraries',
+ collapsed: true,
+ items: [
+ 'migration/mocking/moq',
+ 'migration/mocking/nsubstitute',
+ 'migration/mocking/fakeiteasy',
+ ],
+ },
],
},
{
diff --git a/skills/tunit/SKILL.md b/skills/tunit/SKILL.md
index 57fc92072b4..dd5e60e5497 100644
--- a/skills/tunit/SKILL.md
+++ b/skills/tunit/SKILL.md
@@ -1,6 +1,6 @@
---
name: tunit
-description: Write or troubleshoot tests using TUnit, TUnit.Assertions, or TUnit.Mocks, or migrate tests to TUnit. Routes to task-specific official documentation. Use only for tasks involving these packages or migration to TUnit.
+description: Write or troubleshoot tests using TUnit, TUnit.Assertions, or TUnit.Mocks, or migrate tests or mocks to TUnit or TUnit.Mocks. Routes to task-specific official documentation. Use only for tasks involving these packages or migration to them.
license: MIT
---
@@ -32,6 +32,7 @@ Choose the link that matches the task; these are alternatives, not a reading che
| Run tests or select tests | [Running tests](https://tunit.dev/docs/getting-started/running-your-tests.md) or [filters](https://tunit.dev/docs/execution/test-filters.md) |
| Migrate an existing suite | [xUnit](https://tunit.dev/docs/migration/xunit.md), [NUnit](https://tunit.dev/docs/migration/nunit.md), or [MSTest](https://tunit.dev/docs/migration/mstest.md), matching the source framework |
| Mocking | [TUnit.Mocks](https://tunit.dev/docs/writing-tests/mocking.md) |
+| Migrate mocks to TUnit.Mocks | [Moq](https://tunit.dev/docs/migration/mocking/moq.md), [NSubstitute](https://tunit.dev/docs/migration/mocking/nsubstitute.md), or [FakeItEasy](https://tunit.dev/docs/migration/mocking/fakeiteasy.md), matching the source library |
| Aspire integration testing | [Aspire](https://tunit.dev/docs/examples/aspire.md) |
| ASP.NET Core integration testing | [ASP.NET Core](https://tunit.dev/docs/examples/aspnet.md) |
| Playwright browser testing | [Playwright](https://tunit.dev/docs/examples/playwright.md) |
diff --git a/tests/TUnit.DocTests/TUnit.DocTests.csproj b/tests/TUnit.DocTests/TUnit.DocTests.csproj
index 8f74624afbb..3e94ef8315f 100644
--- a/tests/TUnit.DocTests/TUnit.DocTests.csproj
+++ b/tests/TUnit.DocTests/TUnit.DocTests.csproj
@@ -38,6 +38,7 @@
+
@@ -45,6 +46,7 @@
+
diff --git a/tools/TUnit.DocSnippetGenerator/Program.cs b/tools/TUnit.DocSnippetGenerator/Program.cs
index 453a5c18428..23b9e524b28 100644
--- a/tools/TUnit.DocSnippetGenerator/Program.cs
+++ b/tools/TUnit.DocSnippetGenerator/Program.cs
@@ -436,6 +436,7 @@ static string GenerateSource(
else
{
builder.AppendLine($"namespace {generatedNamespace};");
+ AppendMockingLibraryUsings(builder, snippet);
}
builder.AppendLine($"#line {snippet.Line} \"{snippet.SourcePath}\"")
@@ -504,6 +505,7 @@ static string GenerateSource(
}
builder.AppendLine($"namespace {generatedNamespace};");
+ AppendMockingLibraryUsings(builder, snippet);
if (containsExtensionMethod)
{
@@ -691,6 +693,36 @@ static void AppendFrameworkAliases(StringBuilder builder, Snippet snippet)
}
}
+// Mocking-library migration pages compare Moq, NSubstitute, and FakeItEasy with TUnit.Mocks.
+// Their type names (Mock, Times, MockBehavior, Arg) clash with TUnit.Mocks' global usings,
+// so a fence marked with the library's name imports it inside the namespace, where lookup
+// finds it before the global usings.
+static void AppendMockingLibraryUsings(StringBuilder builder, Snippet snippet)
+{
+ if (!snippet.SourcePath.Contains("/migration/mocking/", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+
+ var marker = Regex.Match(snippet.Source, @"(?m)^\s*//\s*(Moq|NSubstitute|FakeItEasy)\s*$");
+ if (!marker.Success)
+ {
+ return;
+ }
+
+ var namespaces = marker.Groups[1].Value switch
+ {
+ "Moq" => new[] { "Moq" },
+ "NSubstitute" => new[] { "NSubstitute", "NSubstitute.ExceptionExtensions", "NSubstitute.ReceivedExtensions" },
+ _ => new[] { "FakeItEasy" }
+ };
+
+ foreach (var ns in namespaces)
+ {
+ builder.AppendLine($"using {ns};");
+ }
+}
+
static string QualifyLocallyDeclaredAttributeTypes(string attribute, string source, string generatedNamespace)
{
var declaredTypes = Regex.Matches(