Skip to content

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 Moq

Getting started

The smallest useful thing you can do with it, and what each part means.

Setup and verification
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();
VerifyNoOtherCalls is underused and valuable — it catches an unexpected extra call that Verify alone would let through.

Advanced usage

Where the library earns its place over a simpler alternative.

Strict mocks, sequences and callbacks
// 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);
Strict mocks turn silent default returns into loud failures, which surfaces the case where production code calls something the test never anticipated.

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.