Testen, DI und EJBs
Interessanterweise ist es immer noch schwer, die DI Vorteile wirklich plastisch darzustellen. Zur Verdeutlichung sollte man sich nochmal EJB 2.1 vergegenwärtigen. Wie teste ich dort eine Anwendung? Die entscheidene Frage ist vor allem, wie ich Unit Tests umsetze. Dort kann ich die Anwendung in einen Application Server deployen. Schon dieser Vorgang alleine dauert länger, als ein Unit Test dauern sollte - keine gute Idee.
Also muss ich mir etwas anderes einfallen lassen. Ich sollte die Anwendung zwischen Technologie (EJB) und Logik aufteilen. Dazu gibt es Ansätze wie den Business Delegate, an den ich die Aufrufe der EJBs delegieren. Das ist fast gut, impliziert jedoch entweder den Gebrauch eines Generators oder viel Code Duplikation. Na ja, aber ich habe jetzt meine normalen Java Objekte, die ich mit JUnit einfach testen kann. Übrigens habe ich hier bei bei Entity Beans mit EJB 2.1 ein echtes Problem, denn die wesentliche Eigenschaft (Persistenz) ist außerhalb eines Application Servers nicht testbar. Sicherheit kann ich ebenfalls nicht testen, ist aber für Unit Tests nicht relevant. Transaktionen wären vielleicht relevant, aber sind hier auch nicht testbar. Schlimmer ist, dass ich alle Ressourcen, auf die mir ein Application Server Zugriff bietet, nur über JNDI erreichbar sind. Hier kann ich einen Service Locator verwenden, in den ich alle JNDI Zugriffe auslagere. Wenn ich testen will, schiebe ich dem Service Locator einfach Testobjekte unter. Die andere Möglichkeit ist es, direkt im JNDI andere Objekte zu registrieren und eine JNDI Implementierung außerhalb des Application Servers zu nutzen.
Soweit ist das Vorgehen auch ein "offiziell authorisiertes" EJB Vorgehen, will heißen: Jeder gute EJB Consultant empfiehlt es. Dependency Injection geht hier nur einen kleinen Schritt weiter, indem es den Service Locator durch eine Infrastruktur ersetzt, die den einzelnen Java Objekte die Referenzen auf Ressourcen zuweist, statt dass die Objekte sie selber heraussuchen müssen. Was das bedeutet? Dependency Injection ergibt sich fast zwangsläufig aus dem Anspruch, EJB Anwendungen testbar zu machen. Schon diese Argumentationskette reicht meiner Meinung nach als Begründung für DI aus. Wer EJB 2.1 Anwendungen ohne Application Server testen will, landet fast automatisch bei normalen Java Objekten und DI.
Die Frage ist nun, ob man eine solche Infrastruktur selber schaffen will, oder ob man nicht ein kostenloses Open Source Framework wie z.B. Spring verwendet. Zusätzlich ist es in Bezug auf Transaktionen von der Umgebung unabhängig, so dass man auch dies in einem Kontext ohne Application Server z.B. mit einer In-Memory Datenbank wie HSQL testen kann, wenn man mit Datenbank testen will. Übrigens ist genau dies auch der Grund, warum Spring eine bessere Lösung ist als EJB 3: Die Transaktionen in EJB 3 sind für EJB Umgebungen definiert, was im Moment bedeutet, dass sie nur auf Application Servern funktionieren. Spring Transaktionen gehen auch mit einfachen JDBC Connections...
Ist also DI nur eine Erleichterung für Tests? Meiner Meinung nach nicht, weil es auch eine flexilblere Architektur bietet, in der man einfacher Services als einfache Java Objekte komponieren kann und vorgefertigte Konfigurationsmöglichkeiten bekommt. Außerdem sind Techniken wie Spring AOP erst so möglich und auch den Export als Web Services oder per RMI erleichtert das Modell. Also: DI ist mehr als "nur" einfache Testbarkeit, aber Testen reicht meiner Meinung nach als Begründung für DI schon aus.