Zurück zum Blog
Clean Code März 2026 8 Min Lesezeit

Clean Code #7: Testing — Tests als Qualitätsgarantie

MN

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:

  1. Red: Schreiben Sie einen fehlschlagenden Test
  2. Green: Schreiben Sie den minimalen Code, der den Test bestehen lässt
  3. 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

Interesse geweckt?

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.

Kontakt aufnehmen