AutoMock.Generator
1.3.0
dotnet add package AutoMock.Generator --version 1.3.0
NuGet\Install-Package AutoMock.Generator -Version 1.3.0
<PackageReference Include="AutoMock.Generator" Version="1.3.0" />
<PackageVersion Include="AutoMock.Generator" Version="1.3.0" />
<PackageReference Include="AutoMock.Generator" />
paket add AutoMock.Generator --version 1.3.0
#r "nuget: AutoMock.Generator, 1.3.0"
#:package AutoMock.Generator@1.3.0
#addin nuget:?package=AutoMock.Generator&version=1.3.0
#tool nuget:?package=AutoMock.Generator&version=1.3.0
AutoMock.Generator
Compile-time mocking for .NET using Roslyn source generators. Add [Mock(typeof(IFoo))] to a partial
class — AutoMock generates a plain, debuggable test double implementing IFoo at build time, with a
settable *_Handler delegate and a *_Calls argument log for every member. No reflection, no
Castle.Core dynamic proxies — a compile-time alternative to Moq / NSubstitute for interfaces, fully
AOT/trim-safe.
Why
Moq and NSubstitute build mocks at runtime via System.Reflection.Emit / Castle.DynamicProxy. That:
- Doesn't work (or needs extra configuration) under Native AOT / trimming.
- Adds startup cost building proxy types.
- Produces an implementation you can't set a breakpoint in or read.
AutoMock generates a normal, debuggable partial class per [Mock] usage, at build time. You can read
it, step into it, and it fails the build (not the test run) if the interface has a member AutoMock
can't yet generate.
Usage
using AutoMock;
public interface ICalculator
{
int Add(int a, int b);
Task<int> AddAsync(int a, int b);
void Reset();
string Name { get; set; }
}
[Mock(typeof(ICalculator))]
public partial class CalculatorMock
{
}
Generates a CalculatorMock implementing ICalculator:
var mock = new CalculatorMock
{
Add_Handler = (a, b) => a + b, // configure return behavior
};
mock.Add(2, 3); // 5
mock.Add_CallCount; // 1
mock.Add_Calls[0]; // object?[] { 2, 3 }
ICalculator asInterface = mock; // implements the interface directly
ref/out/in parameters
public interface IParser
{
bool TryParse(string input, out int value);
}
[Mock(typeof(IParser))]
public partial class ParserMock { }
var mock = new ParserMock
{
TryParse_Handler = (string input, out int value) =>
{
value = int.Parse(input);
return true;
},
};
mock.TryParse("42", out var result); // result == 42
Verifying calls — Times
var mock = new CalculatorMock();
mock.Add(1, 2);
mock.Add_Verify(Times.Once()); // passes
mock.Add_Verify(Times.Exactly(2)); // throws AutoMockVerificationException
mock.Reset_Verify(Times.Never()); // passes — Reset() was never called
mock.Name_VerifyGet(Times.AtLeast(1));
mock.Name_VerifySet(Times.Once());
Times supports Once(), Never(), Exactly(n), AtLeast(n), AtMost(n), and Between(min, max).
Argument matchers
Verify that a method was called with specific arguments using It:
mock.Add(1, 2);
mock.Add_Verify(Times.Once(), It.IsAny<int>(), 2); // matches any first arg, literal second arg
mock.Add_Verify(Times.Once(), It.Is<int>(a => a > 0), 2); // predicate matcher
mock.Add_Verify(Times.Never(), 99, 99); // plain values are compared with Equals
It.IsAny<T>(), It.Is<T>(predicate), and It.IsNotNull<T>() are available; unmatched positions can also be
plain literal values. The matcher overload is only generated for methods that take parameters.
Every generated member gets:
| Suffix | Purpose |
|---|---|
{Member}_Handler |
Func<..>/Action<..> delegate you set to control the return value / side effect. If unset, methods return default/Task.CompletedTask/Task.FromResult(default). |
{Member}_Calls |
List<object?[]> — every invocation's arguments, in order. |
{Member}_CallCount |
Shorthand for {Member}_Calls.Count. |
{Member}_WasCalled |
Shorthand for {Member}_CallCount > 0. |
{Member}_Verify(Times) |
Throws AutoMockVerificationException if the call count doesn't match Times. |
{Method}_Verify(Times, params object?[] matchers) |
Same, but also requires each call's arguments to match matchers (literal values or It.* matchers). Only generated for methods with parameters. |
Properties additionally get {Name}_GetCallCount / {Name}_SetCallCount counters; the getter/setter
themselves just round-trip a private backing field.
Requirements
- The target class must be
partial. - The
[Mock]constructor argument must be an interface type ([Mock(typeof(IFoo))]). - A class can implement multiple interfaces via multiple
[Mock]attributes.
Supported members (v1.3.0)
- Methods: synchronous,
void,Task, andTask<T>returning, with any number ofref/out/inor by-value parameters. Methods withref/out/inparameters get a dedicated per-method delegate type ({Method}Delegate) sinceFunc<>/Action<>can't express those signatures. - Properties: get-only, set-only, and get/set.
- Inherited interface members (interfaces that extend other interfaces).
AutoMock_Reset()— clears every generated*_Handler,*_Callslog, and property backing field, so a single mock instance can be reused across tests (e.g. a shared xunit fixture).{Member}_WasCalled— shorthand for{Member}_CallCount > 0.{Member}_Verify(Times)/{Property}_VerifyGet(Times)/{Property}_VerifySet(Times)— Moq-style call-count verification (Times.Once(),Times.Exactly(n),Times.AtLeast(n), etc.), throwingAutoMockVerificationExceptionon mismatch.{Method}_Verify(Times, params object?[] matchers)— verifies call count and arguments, usingIt.IsAny<T>(),It.Is<T>(predicate),It.IsNotNull<T>(), or plain literal values.
Not yet supported (v1.3.0 — see Roadmap)
Skipped with an AM003 info diagnostic (build still succeeds — implement these manually in the partial class if you need them):
- Generic methods.
- Indexers.
- Events.
Diagnostics
| ID | Severity | Meaning |
|---|---|---|
| AM001 | Error | [Mock] target class is not partial. |
| AM002 | Error | [Mock] argument is not an interface type. |
| AM003 | Info | Member skipped — unsupported shape (generic method / ref-out-in param / indexer / event). |
Roadmap
- Generic method support (likely requires
Delegate.DynamicInvoke-based handlers — a deliberate reflection tradeoff for that specific case, called out explicitly rather than silently applied). - Abstract class mocking (in addition to interfaces).
- Sequential setups (return different values on successive calls).
License
MIT
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.
1.3.0: Argument matchers — It.IsAny<T>(), It.Is<T>(predicate), It.IsNotNull<T>() for use with a new {Method}_Verify(Times, params object?[] matchers) overload, e.g. mock.Add_Verify(Times.Once(), It.IsAny<int>(), 2). 1.2.0: Moq-style verification — Times.Once()/Never()/Exactly(n)/AtLeast(n)/AtMost(n)/Between(min,max), generated {Method}_Verify(Times) and {Property}_VerifyGet/VerifySet(Times) methods, throwing AutoMockVerificationException on mismatch. 1.1.0: ref/out/in parameter support (generates a dedicated per-method delegate type when Func/Action can't express the signature); *_WasCalled shorthand per method; AutoMock_Reset() clears every Handler/Calls/property backing field so a mock instance can be reused across tests. 1.0.0: Initial release. [Mock(typeof(IFoo))] on a partial class generates a test double implementing the interface with per-member `*_Handler` delegates, `*_Calls` argument logs, and `*_CallCount`. Supports methods (sync, Task, Task<T>) and get/set properties. AM001 (target must be partial), AM002 (argument must be an interface type), AM003 (unsupported member: generic method, indexer, or event — skipped).