JUnit für Fortgeschrittene [email protected] [email protected] 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 2 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, ...) 3 Kurze Wiederholung • JUnit macht Spaß... ... 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 4 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 5 Übersicht • Einführung Mock Objects • Programmgrenzen: I/O, Netzwerk, DB • „static“ und andere Hindernisse • EJBs unter freiem Himmel • Zusammenfassung • Fragen und Diskussion 6 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 Schufaanfrage Netzwerk Kundenpersistenz 7 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 8 Mock Objects • Code über Interface ansprechen • Test-Implementierung für JUnit-Test • Initialisierung: Konstruktor oder per Parameter Statistik StatistikDatenquelle KundenStatistikDatenquelle StatistikTest MockDatenquelle Kundenverwaltung 9 Praktisches Beispiel • Ein Quelltext sagt mehr als tausend Folien... 10 Konkretes Vorgehen • Mock Object initialisieren Zustand setzen Verhalten parametrisieren • Mock Object an getesteten Code übergeben • Zustand des Mock Objects verifizieren 11 Größere Perspektive • Testbarkeit prägt das Design! explizite Abhängigkeiten Refactoring • Verschiedene Anwendungsgebiete Geschäftslogik Systemschnittstellen Logger etc. 12 Übersicht • Einführung • Mock Objects Programmgrenzen: I/O, Netzwerk, DB • „static“ und andere Hindernisse • EJBs unter freiem Himmel • Zusammenfassung • Fragen und Diskussion 13 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 14 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 15 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 HttpServComm Netzwerk TimeoutServComm 16 Praktisches Beispiel • Ein Quelltext sagt mehr als tausend Folien... 17 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 18 Testdaten • „automtatisch“: Jeder Testfall erzeugt alle benötigten Daten • „schnell“: leere Datenbank • „einfach“: Bei Bedarf Refactoring gemeinsam genutzte Testdatenerzeugung 19 Übersicht • Einführung • Mock Objects • Programmgrenzen: I/O, Netzwerk, DB „static“ und andere Hindernisse • EJBs unter freiem Himmel • Zusammenfassung • Fragen und Diskussion 20 „static ist böse“ • statischer Zustand ist problematisch schlechte Wiederverwendbarkeit keine unabhängige Testkonfiguration implizite Querabhängigkeiten von Tests • statischer Code ist okay 21 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... 22 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! 23 Auswirkungen auf das Design • Lego-Baukasten sehr flexibel oft wiederverwendbar • separat testbare Systemteile • dynamisch konfiguriert Gefahr, dass unzusammenhängend und dadurch kompliziert („Ravioli“) • Refactoring 24 Tests auf Systemebene • Zusammenhang durch Gesamttest Black Box Konkrete Integration des Zielsystems testen • Es gibt andere Arten, Systeme zu entwerfen Aber mit geringerer Testabdeckung 25 Übersicht • Einführung • Mock Objects • Programmgrenzen: I/O, Netzwerk, DB • „static“ und andere Hindernisse EJBs unter freiem Himmel • Zusammenfassung • Fragen und Diskussion 26 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 27 ... - 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 28 Ziel: separat testen • Komponenten-Gedanke: getrennt entwickelbar frei kombinierbar • Praktische Probleme: Konfigurations-Parameter JNDI DataSource ... 29 „Delegate“ XyzBean XyzDelegate JNDI etc. • Logik in separate Klasse auslagern, EJB delegiert Interaktion mit App-Server nur in EJB Delegate ist lauf- und testfähig ohne Container EJB „beliefert“ 30 „Business Interface“ AbcDelegate AbcBean XyzBI EJBObject XyzRemote • „Business Interface“ mit den fachlichen Methoden Remote-Interface erbt vom fachlichen Interface fremder Delegate kann vom BI abhängen 31 z.B. Begrüßungsservice • Begrüßungs-EJB holt den Namen von Kundenmanager-EJB BegruesserDelegate KundenMgrBI KundenMgrRemote KundenMgrBean BegruesserBean KundenMgrHome 32 Praktisches Beispiel • Ein Quelltext sagt mehr als tausend Folien... 33 Was ist passiert? • Business Interface 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 34 Übersicht • Einführung • Mock Objects • Programmgrenzen: I/O, Netzwerk, DB • „static“ und andere Hindernisse • EJBs unter freiem Himmel Zusammenfassung • Fragen und Diskussion 35 Mock Objects • Abhängigkeiten zwischen Klassen erschweren das Testen. • Abhängigkeiten auflösen durch Interfaces • Test-Code verwendet spezielle TestImplementierungen • Kapselung von Programmgrenzen 36 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 37 Los geht´s • „Es gibt nichts Gutes außer man tut es“ gute Testabdeckung ist möglich Es lohnt sich Testen macht Spaß Refactoring 38 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 39 Übersicht • Einführung • Mock Objects • Programmgrenzen: I/O, Netzwerk, DB • „static“ und andere Hindernisse • EJBs unter freiem Himmel • Zusammenfassung Fragen und Diskussion 40