Mocking in C# with Moq and NSubstitute
Mocking is an essential technique in C# unit testing that isolates the code under test by replacing external dependencies with controlled, simulated objects. This guide explains the core concepts of mocking and provides practical, direct examples using two of the most popular .NET mocking frameworks: Moq and NSubstitute. You will learn how to configure return values, verify interactions, and choose the right library for your test suite.
What is Mocking?
In unit testing, your classes often depend on external resources such as databases, web APIs, or file systems. Testing these dependencies directly introduces latency, instability, and side effects.
Mocking solves this problem by creating lightweight, fake implementations of interfaces or abstract classes. A mock allows you to:
- Define predetermined return values for specific inputs (stubbing).
- Inspect whether specific methods were called, how many times, and with which arguments (verification).
- Isolate the System Under Test (SUT) to ensure that test failures point directly to logic errors in the class being tested.
Using Moq
Moq is one of the most widely adopted mocking libraries in the .NET ecosystem. It relies heavily on LINQ expression trees and lambda expressions to configure behavior and assertions.
Setup and Return Values
To mock an interface using Moq, instantiate
Mock<T>, configure method behavior using
.Setup(), and pass mock.Object to your
class:
using Moq;
using Xunit;
public interface IUserRepository
{
User GetUserById(int id);
void Save(User user);
}
public class UserServiceTests
{
[Fact]
public void GetUserName_WhenUserExists_ReturnsFullName()
{
// 1. Arrange
var mockRepo = new Mock<IUserRepository>();
mockRepo.Setup(repo => repo.GetUserById(1))
.Returns(new User { Id = 1, Name = "Jane Doe" });
var service = new UserService(mockRepo.Object);
// 2. Act
var result = service.GetUserName(1);
// 3. Assert
Assert.Equal("Jane Doe", result);
}
}Verifying Method Execution
Moq provides the .Verify() method to confirm whether a
dependency was invoked:
[Fact]
public void RegisterUser_ValidUser_CallsSaveMethodOnce()
{
// Arrange
var mockRepo = new Mock<IUserRepository>();
var service = new UserService(mockRepo.Object);
var newUser = new User { Name = "John Smith" };
// Act
service.RegisterUser(newUser);
// Assert
mockRepo.Verify(repo => repo.Save(It.IsAny<User>()), Times.Once);
}Using NSubstitute
NSubstitute is designed to provide a cleaner, more fluent API. It minimizes the need for lambdas and wrapper classes by allowing you to call methods directly on the substituted instance.
Setup and Return Values
Instead of instantiating a wrapper, you create a substitute directly
via Substitute.For<T>():
using NSubstitute;
using Xunit;
public class UserServiceNSubstituteTests
{
[Fact]
public void GetUserName_WhenUserExists_ReturnsFullName()
{
// 1. Arrange
var repo = Substitute.For<IUserRepository>();
repo.GetUserById(1).Returns(new User { Id = 1, Name = "Jane Doe" });
var service = new UserService(repo);
// 2. Act
var result = service.GetUserName(1);
// 3. Assert
Assert.Equal("Jane Doe", result);
}
}Verifying Method Execution
NSubstitute uses the .Received() extension method
directly on the substitute object to verify calls:
[Fact]
public void RegisterUser_ValidUser_CallsSaveMethodOnce()
{
// Arrange
var repo = Substitute.For<IUserRepository>();
var service = new UserService(repo);
var newUser = new User { Name = "John Smith" };
// Act
service.RegisterUser(newUser);
// Assert
repo.Received(1).Save(Arg.Any<User>());
}Comparison: Moq vs. NSubstitute
| Feature | Moq | NSubstitute |
|---|---|---|
| Object Creation | new Mock<T>() (requires
.Object access) |
Substitute.For<T>() |
| Method Configuration | mock.Setup(x => x.Method()).Returns(val) |
substitute.Method().Returns(val) |
| Call Verification | mock.Verify(x => x.Method(), Times.Once) |
substitute.Received(1).Method() |
| Design Style | Explicit, lambda-based | Concise, fluent, natural syntax |
Both frameworks effectively isolate dependencies in .NET applications. Moq is a robust standard found in many enterprise codebases, while NSubstitute is often preferred for new projects due to its readable, concise syntax.