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
HelloFlowproject
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<IHelloRepository>();
var service = new HelloService(mockRepo.Object);
// Act
var result = service.GetHello("TestUser");
// Assert
mockRepo.Verify(
x => x.Save(It.IsAny<HelloResponse>()),
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.
This 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 is becoming more challenging, but at the same time it feels more organized.
- I am starting to sense how a system behaves like a factory, where each component plays a specific role and works together.
Top comments (4)
This is a really solid way to frame it — especially for people early in C# who keep hearing “use interfaces” without ever seeing why.
You nailed the core point: interfaces aren’t about abstraction trophies, they’re about control. The moment you can swap a real dependency for a mock and prove behavior in isolation, the whole thing clicks. No DB, no side effects, no guessing — just “did this service do what it promised to do?”
I also like that you focused the test on interaction, not implementation. Verifying Save was called exactly once is a very grown-up test choice. It teaches that unit tests are about behavioral contracts, not re-running the same logic twice.
The factory analogy at the end is spot on too. Once responsibilities are clear and boundaries are enforced, systems stop feeling fragile and start feeling… predictable. That’s when testing stops being scary and starts being boring (in the best way).
Great progress for day 08 — this is one of those concepts that quietly levels people up without them realizing it.
Thank you so much for your encouraging words. Since I’ve been self-curating my own curriculum with the help of AI, I’ve often struggled with self-doubt, wondering if I was heading in the right direction. Your comment has truly given me the strength and motivation to keep pushing forward.
I would love to ask one more question: From a professional's perspective, what is the outlook for C# .NET? As a beginner, I’m not yet familiar with the broader IT landscape, so I would deeply appreciate your insight on this.
That’s a really good question — and it’s one a lot of people don’t ask early enough, so you’re already doing something right.
From a professional perspective, C#/.NET has one of the most stable and durable outlooks in the industry. It’s not the loudest ecosystem on social media, but it quietly runs a massive portion of real-world systems: banking platforms, enterprise backends, government services, cloud tooling, internal infrastructure, and long-lived products that need to be maintained for years, not months.
What I think matters most for you as a beginner is this:
.NET teaches you how systems are designed, not just how features are glued together. Interfaces, dependency injection, testing, separation of concerns — these aren’t “C# things”, they’re professional software engineering concepts that transfer everywhere. Once you internalize them here, you’ll recognize the same patterns in Java, backend Python, Go, or even large-scale frontend systems.
One thing I’ve learned building larger systems is that technologies come and go, but good system thinking compounds. C# and .NET reward that kind of thinking because they push you toward structure, contracts, and clarity early on. That’s why so many companies trust it for critical systems — it scales in both code and people.
So if you’re self-curating your curriculum and focusing on fundamentals like testing and boundaries, you’re not off track at all. You’re building a mental model that will still be useful years from now, regardless of which stack you touch next.
Keep going. Quiet, solid progress like this adds up faster than it looks from the inside.
Thank you so much for this comment.
Hearing encouragement like this from someone with your experience genuinely means a lot to me — it feels like a light along the path.
To be honest, I often question myself while studying.
I wonder whether my approach is really the right one, or whether it’s normal that progress doesn’t always sink in easily. As a human, that doubt and anxiety never fully go away, especially when learning something as deep as software engineering.
I also want to say thank you for consistently liking the content I share. It may seem like a small gesture, but it’s truly encouraging. I imagine you’ve gone through similar phases yourself — and that’s probably why you take the time to show interest and support others.
I hope that one day, after these layers of effort have accumulated and I’ve reached a level I can be proud of, I’ll have the same calmness and generosity to encourage beginners the way you’ve encouraged me.
Thank you again. Your words really matter.