What it is
Moq is the most widely used .NET mocking library, creating test doubles for interfaces and virtual members with a LINQ-based setup syntax.
Create a Mock<T>, configure returns with Setup, pass mock.Object to the code under test, and assert interactions with Verify.
Installation
dotnet add package MoqGetting started
The smallest useful thing you can do with it, and what each part means.
csharp
var repo = new Mock<IBookRepository>();
repo.Setup(r => r.GetAsync(42, It.IsAny<CancellationToken>()))
.ReturnsAsync(new Book { Id = 42, Title = "Dune" });
repo.Setup(r => r.GetAsync(99, It.IsAny<CancellationToken>()))
.ReturnsAsync((Book?)null);
var service = new BookService(repo.Object);
Assert.Equal("Dune", (await service.GetTitleAsync(42)));
repo.Verify(r => r.GetAsync(42, It.IsAny<CancellationToken>()), Times.Once);
repo.VerifyNoOtherCalls();Advanced usage
Where the library earns its place over a simpler alternative.
csharp
// Strict: any unconfigured call throws instead of returning default.
var repo = new Mock<IBookRepository>(MockBehavior.Strict);
// Different results on successive calls.
repo.SetupSequence(r => r.NextAsync())
.ReturnsAsync(new Book())
.ReturnsAsync(new Book())
.ReturnsAsync((Book?)null);
// Capture what was passed.
Book? saved = null;
repo.Setup(r => r.SaveAsync(It.IsAny<Book>(), It.IsAny<CancellationToken>()))
.Callback<Book, CancellationToken>((b, _) => saved = b)
.ReturnsAsync(true);
Assert.Equal("Dune", saved?.Title);Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Expected invocation on the mock at least once, but was never performed
- The arguments did not match the Setup. Loosen with It.IsAny to confirm, then tighten to the real expectation.
- Mock returns null unexpectedly
- The method was never set up, so it returns default. Add the Setup, or use MockBehavior.Strict to make the gap obvious.
Best practices
- Mock interfaces you own; mocking a third-party client couples tests to its design.
- Use VerifyNoOtherCalls to catch unexpected interactions.
- Prefer a real database via Testcontainers over mocking the data layer.
- Consider NSubstitute if the team finds Moq's lambda syntax noisy.
Background
Why it exists, and what it was reacting to.
Moq popularised expression-tree-based mocking in .NET, where the setup reads as a call rather than a string. It remains the default in most .NET codebases.
