TDD w praktyce w C# .NET – Unit Testy, które projektują kod
Test-Driven Development (TDD) w C# .NET to jedno z najbardziej niedocenianych narzędzi profesjonalnego programisty. Wielu developerów słyszało o TDD, część próbowała, ale niewielu stosuje je świadomie i konsekwentnie. Dlaczego? Bo zwykle TDD jest tłumaczone źle – teoretycznie, akademicko, bez realnego kontekstu.
W tym artykule pokażę Ci TDD w praktyce, krok po kroku, na prostym, ale realistycznym przykładzie. Bez lania wody. Bez magii. Tylko kod, testy i decyzje projektowe.
Czym jest Test-Driven Development (TDD)?

Test-Driven Development to podejście do tworzenia oprogramowania, w którym testy jednostkowe powstają przed kodem produkcyjnym. Nie po. Nie „jak będzie czas”. Zawsze na początku.
Klasyczny cykl TDD wygląda tak:
- RED – piszesz test, który nie przechodzi
- GREEN – piszesz minimalny kod, aby test przeszedł
- REFACTOR – upraszczasz i poprawiasz kod
To wszystko. Żadnych dodatkowych kroków.
W TDD test nie jest dodatkiem. Test jest narzędziem projektowym.
Dlaczego warto stosować TDD w C# .NET?
Najważniejsze korzyści
- kod jest testowalny od samego początku
- dokładnie wiesz, co ma robić funkcjonalność
- nie piszesz nadmiarowej logiki
- refaktoryzacja przestaje być ryzykowna
- testy stają się dokumentacją kodu
TDD wymusza myślenie o API, odpowiedzialnościach i granicach klas zanim powstanie bałagan.
Scenariusz: prosta reguła biznesowa
Załóżmy, że pracujemy nad istniejącym projektem w C# .NET.
Chcemy dodać nową funkcjonalność:
bool IsAdult(int age);
Reguła biznesowa
- osoba pełnoletnia ma 18 lat lub więcej
- funkcjonalność nie istnieje w projekcie
Zaczynamy więc dokładnie tak, jak każe TDD – od testu.
Krok 1: Test dla nieistniejącej funkcjonalności (RED)

Tworzymy nową klasę testową:
using DevHobby.Code.RPG.Core.Services;
using FluentAssertions;
namespace DevHobby.Code.RPG.Core.Tests;
public class AgeServiceTests
{
[Fact]
public void IsAdult_ShouldReturnFalse_WhenAgeIsBelow18()
{
// arrange
var service = new AgeService();
// act
var result = service.IsAdult(17);
// assert
result.Should().BeFalse();
}
}
Co widzimy?
- ❌ klasa
AgeServicenie istnieje - ❌ metoda
IsAdultnie istnieje - ❌ test się nie kompiluje
I bardzo dobrze.
To jest poprawny, zdrowy, pierwszy krok w TDD.
Krok 2: Minimalna implementacja (GREEN)

Dodajemy najprostszą możliwą implementację:
namespace DevHobby.Code.RPG.Core.Services;
public class AgeService
{
public bool IsAdult(int age)
{
return false
}
}
Uruchamiamy testy:
- test się kompiluje
- test przechodzi
Kod jest biznesowo błędny, ale spełnia aktualne wymaganie testu. I tylko to się teraz liczy.
Krok 3: Rozszerzenie wymagań i refaktoryzacja

Dodajemy kolejny test:
[Fact]
public void IsAdult_ShouldReturnTrue_WhenAgeIs18OrAbove()
{
// arrange
var service = new AgeService();
// act
var result = service.IsAdult(18);
// assert
result.Should().BeTrue();
}
Test nie przechodzi – i o to chodzi.
Poprawiamy implementację:
public bool IsAdult(int age)
{
return age >= 18;
}
Wszystkie testy są zielone.
➡ Pełny cykl TDD został zakończony.
Co osiągnęliśmy dzięki TDD?
- API zostało zaprojektowane przez testy
- logika powstała dokładnie wtedy, gdy była potrzebna
- brak nadmiarowego kodu
- bezpieczna refaktoryzacja
To nie jest teoria. To codzienna praktyka.
Najczęstsze błędy przy nauce TDD

❌ Pisanie testów po kodzie
Testy stają się wtedy przykrym obowiązkiem.
❌ Zbyt skomplikowane testy
Test ma być prosty i czytelny.
❌ Strach przed czerwonym testem
Czerwony test to sygnał, że idziesz zgodnie z procesem.
Kiedy TDD działa najlepiej?
- przy dodawaniu nowej funkcjonalności
- przy refaktoryzacji legacy code
- przy pracy zespołowej
- gdy kod ma żyć dłużej niż jeden sprint
Co dalej?
- dodawaj kolejne scenariusze testowe
- testuj przypadki brzegowe
- stosuj TDD przy refaktoryzacji istniejącego kodu
Zobacz też:

Call to Action
👉 Zostaw komentarz: czy stosujesz TDD w swoich projektach?
👉 Subskrybuj kanał YouTube, jeśli chcesz więcej praktycznego C#.

