C#.NET - day 08

Published: (January 13, 2026 at 01:04 PM EST)
2 min read
Source: Dev.to

Source: Dev.to

Day 08 : Unit Testing — The Real Reason Interfaces Exist

Proving service behavior without repositories or databases

Introduction

Many tutorials introduce interfaces and immediately move on to databases.
At that point, learners often ask:

“Why did we even create this interface?”

This step answers that question. The real purpose of the interface appears when we start writing unit tests.

🧪 Step : The Proof

The reason we created IHelloRepository was not abstraction for its own sake. It was to make one thing possible:

testing business logic in isolation.

  • We want to test the behavior of HelloService.
  • We do not want to touch memory, databases, or storage logic.
  • We want tests that are fast, predictable, and repeatable.

This is only possible because the service depends on an interface, not a concrete class.

🛠 Preparing the Test Project

A separate test project is created alongside the main application.

  • Test framework: xUnit
  • Mocking library: Moq
  • Reference: the main HelloFlow project

Moq allows us to create fake implementations of interfaces with minimal effort.

🧠 What Are We Actually Testing?

This test verifies a very specific behavior:

When HelloService.GetHello() is called, does it request the repository to save the data exactly once?

We are not testing storage.
We are not testing LINQ.
We are testing behavior.

🧪 Unit Test Code

using HelloFlow.Models;
using HelloFlow.Repositories;
using HelloFlow.Services;
using Moq;
using Xunit;

namespace HelloFlow.Tests;

public class HelloServiceTests
{
    [Fact]
    public void GetHello_Should_Call_Save_In_Repository()
    {
        // Arrange
        var mockRepo = new Mock();
        var service = new HelloService(mockRepo.Object);

        // Act
        var result = service.GetHello("TestUser");

        // Assert
        mockRepo.Verify(
            x => x.Save(It.IsAny()),
            Times.Once
        );

        Assert.Equal("Hello, TestUser!", result.Message);
    }
}

🔍 Test Structure: Arrange → Act → Assert

All professional unit tests follow the same structure:

  • Arrange: prepare the environment and dependencies
  • Act: execute the method under test
  • Assert: verify the expected behavior

This structure scales from small services to large systems.

🧠 Why This Test Matters

This single test proves several important things:

  • Isolation: The service is tested without executing any repository code.
  • Speed: No database, no I/O, no setup cost.
  • Safety: Repository implementations can change without breaking service tests.

It is the foundation of automated testing in CI/CD pipelines and a key concept in DevOps practices.

🧠 One‑Sentence Summary

This step proves that the service behaves correctly — without repositories, databases, or infrastructure.

✍️ My Notes & Reflections

  • As the system grows step by step, it becomes more challenging, but also more organized.
  • I am starting to sense how a system behaves like a factory, where each component plays a specific role and works together.
Back to Blog

Related posts

Read more »

C#.NET - day 04

Step 1.5 : Introducing the Repository Pattern Separating responsibilities to build systems that scale Introduction The core idea of this step is perfect separa...

MiniScript Road Map for 2026

2026 Outlook With 2025 coming to a close, it’s time to look ahead to 2026! MiniScript is now eight years old. Many programming languages really come into their...