JUnit für Fortgeschrittene Arno.Haase@Haase-Consulting.com Arno.Haase@acm.org www.Haase-Consulting.com
Übersicht Einführung Mock Objects Programmgrenzen: I/O, Netzwerk, DB „static“ und andere Hindernisse EJBs unter freiem Himmel Zusammenfassung Fragen und Diskussion Vorwissen abfragen Wer hat Junit in realem Projekt eingesetzt? Erreichte Testabdeckung?
Ziele des Vortrags Separates Testen von Klassen Abhängigkeiten auflösen Testen bis in die Nähe der Systemgrenzen „Reines“ JUnit, nicht darauf aufsetzende Tools (HttpUnit, Cactus, ...)
Kurze Wiederholung JUnit macht Spaß... Funktionalität ist testbar ... aber in der Praxis gibt es manche Hindernisse Funktionalität ist testbar Normalfälle, Fehlerfälle, Integration Methoden-, Klassen-, Systemebene Grenzen Performance-Tests Multithreading GUI
Gute JUnit-Tests Kriterien für eine gute Test-Suite: Schnelles Durchlaufen Gute Abdeckung Vertrauen „vollständig“ ist aber schlechtes Ziel Automatische Ausführbarkeit automatisierter Build-Prozess Einfach zu erstellen / pflegen
Übersicht Einführung Mock Objects Programmgrenzen: I/O, Netzwerk, DB „static“ und andere Hindernisse EJBs unter freiem Himmel Zusammenfassung Fragen und Diskussion Vorwissen abfragen Wer hat Junit in realem Projekt eingesetzt? Erreichte Testabdeckung?
Problem Eine einzelne Klasse ist leicht zu testen. Im echten Projekt ist es oft anders. Wenn Klassen von einander abhängen, kann man sie nur noch zusammen testen. Abhängigkeiten sind oft nur implizit. Statistik Kundenverwaltung Kundenpersistenz Schufaanfrage Netzwerk
Problem (2) sogenannter „Pragmatismus“: Dann testet man eben nicht so gründlich... Sonderfälle bei der Datenbelieferung Fehlerfälle und Exceptions seltene Testausführung wegen Aufwand für Deployment und Infrastruktur
Mock Objects Code über Interface ansprechen Test-Implementierung für JUnit-Test Initialisierung: Konstruktor oder per Parameter Statistik StatistikDatenquelle KundenStatistikDatenquelle StatistikTest MockDatenquelle Kundenverwaltung
Praktisches Beispiel Ein Quelltext sagt mehr als tausend Folien...
Konkretes Vorgehen Mock Object initialisieren Zustand setzen Verhalten parametrisieren Mock Object an getesteten Code übergeben Zustand des Mock Objects verifizieren
Größere Perspektive Testbarkeit prägt das Design! explizite Abhängigkeiten Refactoring Verschiedene Anwendungsgebiete Geschäftslogik Systemschnittstellen Logger etc.
Übersicht Einführung Mock Objects Programmgrenzen: I/O, Netzwerk, DB „static“ und andere Hindernisse EJBs unter freiem Himmel Zusammenfassung Fragen und Diskussion Vorwissen abfragen Wer hat Junit in realem Projekt eingesetzt? Erreichte Testabdeckung?
Grenzen sind komplex Probleme mit Tests: „schnell laufen“: Interaktion kann Zeit kosten „Abdeckung“: Verhalten externer Teile schlechter zu kontrollieren „Automatisch“: Synchronisierung von Tests und externen Systemen „Einfach zu erstellen“: Externer Aufwand Auch bei externen Bibliotheken ***** Wer kennt das!?
Zugriff durch Wrapper Die eigentliche System-Schnittstelle hinter Interface kapseln z.B. „HttpSender“, „FilePersister“, ... „fertige“ Mock Objects Test-Implementierungen können Sonderfälle / Exceptions simulieren Design-Option: Decorator, Caching, Filter etc. Refactoring
z.B. Netzwerkkommunikation Client versendet Strings per HTTP Netzwerkkommunikation über Schnittstelle Mock-Implementierung für Tests weitere nützliche Implementierungen ClientTest MockServComm Client ServerCommunicator NullServComm TimeoutServComm HttpServComm Netzwerk
Praktisches Beispiel Ein Quelltext sagt mehr als tausend Folien...
Datenbanken Alternative: Durchgriff auf die Datenbank Testet Spezialitäten des DB-Systems Testet die eigentliche Persistenzschicht Macht Abhängigkeiten im Datenmodell deutlich Jeder Entwickler braucht eine Datenbank
Testdaten „automtatisch“: Jeder Testfall erzeugt alle benötigten Daten „schnell“: leere Datenbank „einfach“: Bei Bedarf Refactoring gemeinsam genutzte Testdatenerzeugung
Übersicht Einführung Mock Objects Programmgrenzen: I/O, Netzwerk, DB „static“ und andere Hindernisse EJBs unter freiem Himmel Zusammenfassung Fragen und Diskussion Vorwissen abfragen Wer hat Junit in realem Projekt eingesetzt? Erreichte Testabdeckung?
„static ist böse“ statischer Zustand ist problematisch schlechte Wiederverwendbarkeit keine unabhängige Testkonfiguration implizite Querabhängigkeiten von Tests statischer Code ist okay
Factories Nur auf den ersten Blick harmlos kapseln verwendete Implementierung Problem ist nicht die Factory selbst sondern verwendender Code alle Nachteile von statischen Daten Singletons sind problematisch auch JNDI zusätzliche Indirektionsstufen ändern nichts...
Konfigurationsdaten zentrale Stelle für Konfigurationen Properties, Servletparameter, EJB-Parameter, ... per definitionen globale Daten, d.h. static Versuchung, sie „public static“ bekannt zu machen Alternative: Code mit Konfigurationsobjekt parametrieren!
Auswirkungen auf das Design Lego-Baukasten sehr flexibel oft wiederverwendbar separat testbare Systemteile dynamisch konfiguriert Gefahr, dass unzusammenhängend und dadurch kompliziert („Ravioli“) Refactoring
Tests auf Systemebene Zusammenhang durch Gesamttest Black Box Konkrete Integration des Zielsystems testen Es gibt andere Arten, Systeme zu entwerfen Aber mit geringerer Testabdeckung
Übersicht Einführung Mock Objects Programmgrenzen: I/O, Netzwerk, DB „static“ und andere Hindernisse EJBs unter freiem Himmel Zusammenfassung Fragen und Diskussion Vorwissen abfragen Wer hat Junit in realem Projekt eingesetzt? Erreichte Testabdeckung?
EJBs leben im Container... Vorteile: Infrastruktur: JNDI, Transaktionen, ... Erzwungene Trennung von Schnittstelle und Implementierung Aber durch Nachteile erkauft: nur im Container lauffähig Deployment kostet Zeit Deskriptoren legen Implementierungen fest Schwerer zu Debuggen
... - und ihre Tests? „Brute Force“: Deployment und Debugger nicht automatisch, nicht regressionsfähig je nach IDE zeitaufwändig „Black Box“-Tests: Testen der deployten Software mit JUnit Lange Testzyklen schlechte Abdeckung keine Mock Objects
Ziel: separat testen Komponenten-Gedanke: Praktische Probleme: getrennt entwickelbar frei kombinierbar Praktische Probleme: Konfigurations-Parameter JNDI DataSource ...
„Delegate“ Logik in separate Klasse auslagern, EJB delegiert XyzBean XyzDelegate Logik in separate Klasse auslagern, EJB delegiert Interaktion mit App-Server nur in EJB Delegate ist lauf- und testfähig ohne Container EJB „beliefert“ JNDI etc.
„Business Interface“ „Business Interface“ mit den fachlichen Methoden AbcDelegate XyzBI EJBObject „Business Interface“ mit den fachlichen Methoden Remote-Interface erbt vom fachlichen Interface fremder Delegate kann vom BI abhängen AbcBean XyzRemote
z.B. Begrüßungsservice Begrüßungs-EJB holt den Namen von Kundenmanager-EJB BegruesserDelegate KundenMgrBI KundenMgrBean KundenMgrRemote BegruesserBean KundenMgrHome
Praktisches Beispiel Ein Quelltext sagt mehr als tausend Folien...
Was ist passiert? Business Interface Delegate JUnit-Test für Delegate fachliche Schnittstelle der EJB Delegate unabhängig vom Container kennt andere EJBs als Business Interface JUnit-Test für Delegate Mock-Implementierungen für andere EJBs / Business Interfaces
Übersicht Einführung Mock Objects Programmgrenzen: I/O, Netzwerk, DB „static“ und andere Hindernisse EJBs unter freiem Himmel Zusammenfassung Fragen und Diskussion Vorwissen abfragen Wer hat Junit in realem Projekt eingesetzt? Erreichte Testabdeckung?
Mock Objects Abhängigkeiten zwischen Klassen erschweren das Testen. Abhängigkeiten auflösen durch Interfaces Test-Code verwendet spezielle Test-Implementierungen Kapselung von Programmgrenzen
EJBs implizite Abhängigkeiten vom Container (JNDI, Parameter, ...) von anderen EJBs separate Implementierung, EJB als dünner Wrapper reicht Aufrufe durch Business Interface als Schnittstelle ohne technische Methoden
Los geht´s „Es gibt nichts Gutes außer man tut es“ gute Testabdeckung ist möglich Es lohnt sich Testen macht Spaß Refactoring
Literatur http://www.mockobjects.com http://www.easymock.org Dependency Inversion: http://www.objectmentor.com/resources/articles/dip.pdf „Testen von EJBs ohne Application Server“, Java Magazin 10/02
Übersicht Einführung Mock Objects Programmgrenzen: I/O, Netzwerk, DB „static“ und andere Hindernisse EJBs unter freiem Himmel Zusammenfassung Fragen und Diskussion Vorwissen abfragen Wer hat Junit in realem Projekt eingesetzt? Erreichte Testabdeckung?