Clean Code #7: Testing — Tests als Qualitätsgarantie
Michael Nikolaus
Vorstand & Softwarearchitekt, Minicon eG
Code ohne Tests ist per Definition Legacy-Code. Tests geben Ihnen die Freiheit, Code zu ändern, ohne Angst zu haben, etwas kaputt zu machen. Sie sind das Sicherheitsnetz professioneller Entwicklung.
Die drei Gesetze von TDD
Test-Driven Development folgt einem einfachen Zyklus:
- •Red: Schreiben Sie einen fehlschlagenden Test
- •Green: Schreiben Sie den minimalen Code, der den Test bestehen lässt
- •Refactor: Verbessern Sie den Code, ohne die Tests zu brechen
Dieses Muster führt zu Code, der von Anfang an testbar designed ist — statt nachträglich "irgendwie" getestet wird.
F.I.R.S.T. — Eigenschaften guter Tests
- •Fast: Tests müssen schnell laufen — Sekunden, nicht Minuten
- •Independent: Kein Test darf von einem anderen abhängen
- •Repeatable: Gleiche Eingabe → gleiches Ergebnis, immer
- •Self-Validating: Bestanden oder nicht — keine manuelle Prüfung
- •Timely: Tests werden vor oder mit dem Code geschrieben, nicht Wochen später
Anatomie eines guten Tests
// ✅ Arrange-Act-Assert Muster
[Fact]
public void CalculateTotal_WithTwoItems_ReturnsCorrectSum()
{
// Arrange
var cart = new ShoppingCart();
cart.Add(new Product("Laptop", 999.00m));
cart.Add(new Product("Mouse", 29.99m));
// Act
var total = cart.CalculateTotal();
// Assert
Assert.Equal(1028.99m, total);
}Gute Testnamen
Ein Testname sollte beschreiben: Was wird getestet, unter welchen Bedingungen, und was wird erwartet.
// ❌ Nichtssagend
void Test1() { ... }
void TestCalculation() { ... }
// ✅ Beschreibend
void Discount_WhenCustomerIsPremium_Returns20Percent() { ... }
void Login_WithExpiredToken_ThrowsAuthException() { ... }
void Order_WithEmptyCart_IsRejected() { ... }Die Test-Pyramide
Die bewährte Verteilung von Tests:
- •Unit Tests (70%): Schnell, isoliert, testen einzelne Klassen/Methoden
- •Integration Tests (20%): Testen das Zusammenspiel von Komponenten
- •End-to-End Tests (10%): Testen den kompletten Workflow
Je weiter oben in der Pyramide, desto langsamer und fragiler die Tests — deshalb weniger davon.
Was testen?
Testen Sie Verhalten, nicht Implementierung. Ein Test sollte prüfen, was eine Methode tut, nicht wie. Wenn Sie interne Implementierungsdetails testen, brechen Tests bei jedem Refactoring.
// ❌ Testet Implementierung
// "Prüfe ob _repository.Save() genau 1x aufgerufen wurde"
_mockRepo.Verify(r => r.Save(It.IsAny<Order>()), Times.Once);
// ✅ Testet Verhalten
// "Prüfe ob die Order nach dem Speichern abrufbar ist"
var saved = await _service.GetOrder(orderId);
Assert.Equal(expectedTotal, saved.Total);Code Coverage — die richtige Perspektive
80% Code Coverage ist ein gutes Ziel. 100% ist meist Zeitverschwendung — Getter, Setter und triviale Konstruktoren zu testen bringt keinen Mehrwert. Fokussieren Sie sich auf Business-Logik, Edge-Cases und Fehlerszenarien.
Fazit
Tests sind keine optionale Zugabe — sie sind integraler Bestandteil professioneller Softwareentwicklung. Sie ermöglichen Refactoring, dokumentieren Verhalten und geben Ihnen die Zuversicht, dass Ihre Software korrekt funktioniert.
Nächster Artikel: Clean Code #8: Code Reviews — Das Vier-Augen-Prinzip
Lassen Sie uns über Ihr Projekt sprechen
Das erste Gespräch ist kostenlos. Wir hören Ihnen zu und finden die beste Lösung für Sie.