Moq — Essentials

How to mock dependencies to unit test behavior without real implementations.

Setup

  1. Add packages to your test project:
    dotnet add HandsOn.Tests package Moq
    # NUnit already present if you used 'dotnet new nunit'

Example: Service with repository (mocked)

// Domain model
public class Doctor
{
    public int DoctorId { get; set; }
    public string Name { get; set; } = string.Empty;
}

// Dependency to mock
public interface IDoctorRepository
{
    Doctor? GetById(int id);
    void Add(Doctor doctor);
}

// SUT (System Under Test)
public class DoctorService
{
    private readonly IDoctorRepository _repo;
    public DoctorService(IDoctorRepository repo) => _repo = repo;

    public Doctor Register(string name)
    {
        var doc = new Doctor { Name = name };
        _repo.Add(doc);
        return doc;
    }

    public string Describe(int id)
    {
        var d = _repo.GetById(id);
        return d == null ? "Not found" : $"#{d.DoctorId} {d.Name}";
    }
}

// Tests (NUnit + Moq)
using Moq;
using NUnit.Framework;

[TestFixture]
public class DoctorServiceTests
{
    [Test]
    public void Register_AddsDoctor_AndReturnsIt()
    {
        // Arrange
        var mockRepo = new Mock();
        var service = new DoctorService(mockRepo.Object);

        // Act
        var result = service.Register("Dr. Ada");

        // Assert
        mockRepo.Verify(r => r.Add(It.Is(d => d.Name == "Dr. Ada")), Times.Once);
        Assert.That(result.Name, Is.EqualTo("Dr. Ada"));
    }

    [Test]
    public void Describe_ReturnsFormatted_WhenDoctorExists()
    {
        // Arrange
        var mockRepo = new Mock();
        mockRepo.Setup(r => r.GetById(5)).Returns(new Doctor { DoctorId = 5, Name = "Dr. Bob" });
        var service = new DoctorService(mockRepo.Object);

        // Act
        var text = service.Describe(5);

        // Assert
        Assert.That(text, Is.EqualTo("#5 Dr. Bob"));
    }

    [Test]
    public void Describe_ReturnsNotFound_WhenMissing()
    {
        var mockRepo = new Mock();
        mockRepo.Setup(r => r.GetById(It.IsAny())).Returns((Doctor?)null);
        var service = new DoctorService(mockRepo.Object);

        var text = service.Describe(99);
        Assert.That(text, Is.EqualTo("Not found"));
    }
}

Common Moq patterns: Setup to define behavior, Verify to assert calls, It.Is/It.IsAny for argument matching, and Times for call count.

Extra: Throwing and async setups

var mock = new Moq.Mock();
mock.Setup(r => r.GetById(-1)).Throws(new ArgumentException("Invalid id"));

// Async example
public interface IAsyncDoctorRepository { Task GetAsync(int id); }
var m2 = new Moq.Mock();
m2.Setup(r => r.GetAsync(1)).ReturnsAsync(new Doctor { DoctorId = 1, Name = "Async Doc" });