Dirk Richter
Software-Entwicklung und Architektur

Teil 3 - Maßnahmen zur Verbesserung von Unittests


Inhaltsverzeichnis

Zusammenfassung

Test-Suite aufräumen als erster Schritt

Bevor man die Testarchitektur („Testpyramide“) verbesserst, ist es pragmatisch und effektiv, die bestehende Test-Suite zu stabilisieren und aufzuräumen:

Ziel: Eine grüne, schnelle und zuverlässige Testbasis, auf die man sich verlassen kann.


Ice Cream Cone Anti-Pattern/Invertierte Testpyramide beheben

Wenn die Test-Suite aufgeräumt ist, kannst man gezielt die Testarchitektur verbessern:

Ziel: Eine ausgewogene Testpyramide, die schnelle Rückmeldung gibt und sowohl auf niedriger als auch auf höherer Ebene absichert.

Hier ist eine Zuordnung der Maßnahmen zu den vorgeschlagenen Zielen zur Verbesserung von Komponententests, basierend auf der aktuellen Test-Situation. Die Maßnahmen werden jedem Ziel zugeordnet und ausführlich beschrieben.


Erhöhung der Testabdeckung

Maßnahmen:

  1. Fokus auf Komponententests legen:

    • Integrationstests sollten, wo möglich, reduziert und durch zielgerichtete Komponententests ersetzt werden.
    • Einführung klarer Guidelines, die bestimmen, welche Funktionalitäten in Komponententests getestet werden sollen.
  2. Einsatz von Code-Coverage-Tools:

    • Tools wie dotCover, SonarQube oder Visual Studio Coverage einführen, um die Testabdeckung zu messen.
    • Zielabdeckungswerte (z. B. 80 % für Komponententests) definieren und überwachen.

Steigerung der Testqualität

Maßnahmen:

  1. Durchgängige Nutzung des AAA-Patterns:

    • Das Arrange, Act, Assert Pattern standardisiert die Struktur von Tests und macht sie leichter verständlich.
    • Schulungen und Reviews fördern eine konsistente Verwendung.
  2. Einheitliche Benennung der Testmethoden:

    • Testmethodennamen sollten einheitlich und beschreibend sein.
    • Vorschlag: MethodName_StateUnderTest_ExpectedResult.
  3. Trennung von Testkategorien:

    • Komponententests, Integrationstests und Systemtests sollten strikt getrennt in separaten Projekten oder Ordnern für bessere Übersicht und Wartbarkeit ausgeführt werden.
  4. Refactoring von Testklassen:

    • Entfernen von Redundanzen und Konsolidierung von Tests in kleinere, besser wartbare Module.

Reduzierung der Testlaufzeit

Maßnahmen:

  1. Testdaten effizient verwalten:

    • Statt bei jedem Test eine neue Datenbank zu erstellen, Snapshot-Datenbanken verwenden.
    • Mock-Frameworks (z. B. Moq) einsetzen, um Datenbankaufrufe in Komponententests zu simulieren.
    • Vorhandenen Testumgebungsmanager ausbauen.
  2. Parallele Testausführung:

    • Parallele Ausführung unabhängiger Tests, um Gesamtlaufzeiten zu reduzieren.
  3. Langsame Tests optimieren:

    • Verwendung von Profiling-Tools, um langsame Tests zu identifizieren und zu optimieren.
  4. Pipeline verbessern:

    • Eine klare CI/CD-Pipeline definieren, um Tests effizienter zu organisieren, z. B. Trennung von schnellen und langsamen Tests.

Vermeidung von Flaky-Tests

Maßnahmen:

  1. Mocking externer Dienste:

    • Externe Services durch Mocking simulieren, um Abhängigkeiten in Systemtests zu minimieren.
  2. Stubs für externe Abhängigkeiten einführen:

    • Stubs statt direkter API-Calls verwenden, um sicherzustellen, dass Tests unabhängig von externen Systemen stabil laufen.
  3. Testisolation sicherstellen:

    • Unit-Tests sollten von allen externen Abhängigkeiten entkoppelt sein.

Verbesserung der Wartbarkeit und Modularität

Maßnahmen:

  1. Refactoring der Business-Objekte:

    • Starke Vernetzungen der Business-Objekte reduzieren und Abhängigkeiten vereinfachen.
  2. DI-Container standardisieren:

    • Auf einen einzigen Dependency Injection Container umstellen (z. B. Unity), um Komplexität zu minimieren.
  3. Einführen von Seams (Nahtstellen):

    • Strategische Einführung von Nahtstellen in Bereichen mit starker Abhängigkeit (z. B. Datenbank- und API-Zugriffe).
    • Nutzung von Schnittstellen (Interfaces), Factory-Methoden oder Builder-Pattern, um Code modular und testbar zu machen.
    • Abstrahieren schwer testbarer Komponenten durch Wrapper oder Adapter.
  4. Testkategorien strukturieren:

    • Die existierenden 15 Testkategorien konsolidieren und nur die wesentlichen Kategorien beibehalten (z. B. Komponententest, Integrationstest, Systemtest).
  5. Projektstruktur überarbeiten:

    • Testprojekte in eigenständigen Ordnern oder Solutions organisieren, getrennt von der Implementierung.

Automatisierungsgrad erhöhen

Maßnahmen:

  1. Standardisierung der Pipeline:

    • Eine Pipeline definieren, die Tests nach Kategorien trennt und automatisiert ausführt.
    • Automatisierte Trigger in der CI/CD-Pipeline einführen, um Tests nach jedem Build auszuführen.
  2. Automatisierte Code-Coverage-Überwachung:

    • Sicherstellen, dass Code-Coverage-Tools automatisch Berichte erstellen und Abdeckungsziele überwachen.
  3. Testexekution zeitlich optimieren:

    • Schnelle Tests im Millisekundenbereich direkt in der Git-Pipeline ausführen, ressourcenintensive Tests separat behandeln.

Verstärkte Berücksichtigung von Randfällen

Maßnahmen:

  1. Gezielte Tests auf Edge-Cases:

    • Tests gezielt erweitern, um Randfälle wie ungültige Eingaben oder seltene Systemzustände zu adressieren.
  2. Gleichgewicht von Mainstream- und Randfallprüfungen:

    • Sicherstellen, dass auch seltene, aber kritische Szenarien abgedeckt sind.

Schnelleres Schreiben von Unittests

Maßnahmen:

  1. Mocking-Frameworks standardisieren:

    • Hochwertige Mocking Tools wie Moq bereitstellen, um das Schreiben von Tests zu vereinfachen.
  2. Vorbereitende Testdaten bereitstellen:

    • Datenvorlagen bereitstellen, die direkt vom Team genutzt werden können, um Testdaten schneller zu initialisieren.

Erstellung einer Testdokumentation

Maßnahmen:

  1. Dokumentation der Teststrategie:

    • Testprozesse, Testkategorien und Best Practices in einem Dokument festhalten.
    • Beschreibung der Testmethoden, Muster wie das AAA-Pattern und der Namenskonvention.
  2. Testabdeckung dokumentieren:

    • Abdeckungsberichte der Tests fortlaufend dokumentieren, um den Fortschritt zu messen.
  3. CI/CD-Integration dokumentieren:

    • Tests und deren Einbindung in die Pipeline klar beschreiben, um eine einheitliche Nutzung sicherzustellen.

Fazit

Die beschriebenen Maßnahmen adressieren gezielt die aktuellen Probleme und lassen sich klar auf die übergeordneten Ziele zur Verbesserung von Komponententests zurückführen.
Indem Maßnahmen wie die Standardisierung der Pipeline, die Strukturierung der Tests und die Steigerung der Testqualität umgesetzt werden, können langfristig sowohl Stabilität als auch Effizienz der Tests deutlich verbessert werden.
Eine strukturierte Umsetzung ermöglicht es dem Team, die Qualität der Unittests zu steigern und den gesamten Entwicklungsprozess nachhaltig zu verbessern.

#Technicaldebt #Unittests