5 - Testen III: Test Doubles, Fehlermuster, Refactoring
Test Doubles
Problem bei Komponententests
Man kann sie nicht leicht isoliert vom restlichen System Testen weil:
sie miteinander interagieren, andere Schnittstellen aufrufen wie zB die Datenbank
nicht deterministische Werte nutzen wie zB Systemzeit
Test doubles
= Generischer Begriff für Austausch von realen Komponente des Systems durch eine alternative, meist simplifizierte Implementierung für Testzwecke.
Wir möchten Abhängigkeiten zwischen Komponenten ausblenden.
Komponenten mit einfacheren “doubles” ersetzen zum Testen.
Vorteile: Isolation, Keine Abhängigkeiten, geringere Komplexität, Reduktion der Ausführungszeit.
Test Double Typen
Dummy Object
Nicht zum Testen
Nicht zum Verwenden, nicht ausführbar
Quasi “leeres” Argument - Platzhalter ohne Funktionalität
zBDummyCustomer
Klasse implementiertICustomer
aber wirftNotImplementedException
Fake Object
Nicht zum Testen
Zum Verwenden, ausführbare Implementierung
Wenn reale Implementierung zu langsam oder nicht verfügbar
zB simulierte Datenquelle, In-Memory Datenbank → keien Echtdaten
Stub
Zum Testen
Zum Verwenden, ausführbare Implementierung
Liefert vordefinierte Werte, Exceptions indem Pfad vorbestimmt wird.
Erlaubt Testen von Pfaden die von außen nicht beeinflusst und durchlaufen werden können.
Beispiel: Asynchrone Abfrage an einem Server
Original
Stub
Mock
Gleich wie Stub, aber die Parameter die an Mock gegeben werden, werden auch im Test überprüft.
Mock erkennt wenn unerwartete Werte erhalten werden - Assertion und Exception.
Fortsetzung Beispiel: Asynchrone Abfrage an einem Server
Mock - Version 1: Ohne Assertions
Mock - Version 2: Mit Assertions
Spy
Proxy Objekt - Einzelne Methoden durch andere Implementierung ersetzt.
Mocking Frameworks
Mocking Frameworks
vereinfachen Verwendung für Mocks: Unterstützen Erstellung, Konfiguration, Überprüfung
zB Mockito, JMockit, EasyMock, PowerMock, ...
Statische code Analyse (toolgestützt)
toolgestützte Code Analysen für statische QS-Methoden:
Tools: FindBugs/SpotBugs, SonarLint, SonarQube
Statische Code Analyse / Fehlermuster
Verbessert Code Qualität, Wartbarkeit, reduziert Fehler
Häufige Fehlermuster im Code finden wie:
• Variablen mit undefiniertem Wert • Komplexe Konstrukte • Toter Code • Potenzielle Endlosschleifen • Security Schwachstellen • Unused Code • …
Regeln eingeteilt in:
• Bug Potenzielle Fehler • Vulnerability Sicherheitslücken • Code Smell Unschöner/unwartbarer Code
Refactoring
Motivation
Design “verwahrlost” mit der Zeit
Bad Smells zeigen das Refactoring notwendig ist
“Technische Schuld”: Design vernachlässigt um kurz effizienter zu sein
Refactoring
Code Struktur ändern für bessere:
Lesbarkeit, Verständlichkeit, interne Architektur/Design
Funktionalität, Fehler bleiben gleich
Ziel ist es nicht die Performance zu verbessern
Klare Struktur durch Kapselung, Lesbarkeit:
Leichtere Einarbeitung von neuen Entwicklern
Bessere Wartbarkeit, Anpassbarkeit, Erweiterbarkeit
Geringerer Aufwand beim Testen, Leichtere Identifikation von Fehlern
Vorgehensweise
- Identifikation Stelle im Code manuell oder mit Tool finden
- Testabdeckung Sicherstellen, dass die Stelle abgedeckt ist
-
Durchführung umbauen, testen (Funktionalität bleibt gleich)
Patterns als allgemeine Lösungen für widerkehrende Probleme
Bad Smells
Kennzeichen von schlechten Designs - zeigen wo Refactoring notwendig ist.
Beispiele (nach Martin Fowler):
• Duplicated Code • Long Method • Large Class • Long Parameter List • Shotgut Surgery: Kleine Änderungen am Code führen zu Anpassungen in vielen Klassen • Feature Envy: Eine andere Klasse hat mehr Nutzen für eine Funktion • …
Patterns
Allgemeine Lösungen für wiederkehrende Probleme (Bad Smells)
Unterteilung in Gruppen:
• Composing Methods • Moving Features Between Objects • Organizing Data • Simplifying Conditional Expressions • Simplifying Method Calls • Dealing With Generalization