Mock Objects and Fixtures in C#: The Secret to Perfect Unit Tests

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Why Your Tests Are Lying, and How to Fix It?

\n\n

Imagine: you write perfect C# code, cover it with tests, the green checkmark lights up, the CI pipeline is happy. You ship the release… and production crashes. Sound familiar? Most likely, the problem isn't in the code, but in the tests. They weren't testing your real code, but a "toy" version tied to a database, file system, or external API.

\n\n

Welcome to the world of mock objects and fixtures — two pillars that support high-quality unit testing in C#. Without them, your tests are fragile integration checks that break at the slightest change in the environment. With them, you get fast, isolated, and reliable tests that truly protect your code.

\n\n

In this article, we'll break down: how mock differs from stub and fake, how to properly configure fixtures, and show live examples with popular libraries: Moq, NSubstitute, and AutoFixture. Let's go!

\n\n

Mock, Stub, Fake — What's the Difference? (Spoiler: It Matters)

\n\n

Before writing code, let's agree on terminology. Many developers use the word "mock" for everything, but this leads to confusion. In Gerard Meszaros's classification (book "xUnit Test Patterns"), there is a clear distinction:

\n\n
    \n
  • Dummy — an object that is passed but never used. Needed only to fill parameters.
  • \n
  • Stub — provides pre-prepared answers to calls. You check state (state verification).
  • \n
  • Fake — a working but simplified implementation (e.g., InMemoryRepository instead of a real database).
  • \n
  • Mock — an object that checks behavior (behavior verification). You assert that a specific method was called with specific arguments.
  • \n
\n\n

In practice, in C# we most often use mock objects (via Moq or NSubstitute) to verify interactions, and fixtures (via AutoFixture) for quick test data generation. But let's take it step by step.

\n\n

Mock Objects in C#: Isolating Dependencies

\n\n

Imagine you have an OrderService that, when placing an order, sends an email and saves data to the database. Testing it "for real" means sending emails and writing to the database every time. This is slow, unreliable, and expensive.

\n\n

The solution is dependency isolation. We replace real objects (EmailSender, DbContext) with mock objects and verify that the service calls the required methods with the correct parameters.

\n\n

Example with Moq (the most popular library)

\n\n
public interface IEmailSender\n{\n    void Send(string to, string subject, string body);\n}\n\npublic interface IOrderRepository\n{\n    void Save(Order order);\n}\n\npublic class OrderService\n{\n    private readonly IEmailSender _emailSender;\n    private readonly IOrderRepository _repository;\n\n    public OrderService(IEmailSender emailSender, IOrderRepository repository)\n    {\n        _emailSender = emailSender;\n        _repository = repository;\n    }\n\n    public void PlaceOrder(Order order)\n    {\n        // Business logic\n        _repository.Save(order);\n        _emailSender.Send(order.CustomerEmail, "Order Confirmed", $"Your order #{order.Id} has been placed.");\n    }\n}
\n\n

Now let's write a test using Moq:

\n\n
[TestFixture]\npublic class OrderServiceTests\n{\n    [Test]\n    public void PlaceOrder_ShouldSendEmail_WhenOrderIsValid()\n    {\n        // Arrange\n        var mockEmailSender = new Mock<IEmailSender>();\n        var mockRepository = new Mock<IOrderRepository>();\n        var service = new OrderService(mockEmailSender.Object, mockRepository.Object);\n        var order = new Order { Id =                

Blogs

Book Recommendations