Donnerstag, 31. Oktober 2013

JUnit Rules

Vor einiger Zeit bin ich zufällig über eine weniger bekannte Funktionalität von JUnit gestoßen: JUnit Rules.

Das Problem

Mit dem Rules Konstrukt verfügt JUnit seit einer ganzen Weile über die Möglichkeit, den Testablauf zu beeinflussen, also z.B. vor oder nach einem Test etwas zu tun.
Das klingt erstmal absolut unspannend, immerhin sind Methoden, die mit @Before und @After Annotationen versehen werden nicht gänzlich unbekannt. Also was soll das Ganze?

Versuchen wir es mal mit einem einfachen Beispiel:

Das Ergebnis davon sieht wenig überraschend wie folgt aus:

vor dem Test...
test
nach dem Test...


Nehmen wir an, uns gefällt was in den before() und after() Methoden passiert und wir möchten das wiederverwenden. Nichts einfacher als das:

Das Ergebnis der Ausführung dieser Klasse mit Hilfe von JUnit sieht wie folgt aus:

vor dem Test...
extended test
nach dem Test...
vor dem Test...
test
nach dem Test...


Durch Vererbung von JUnit Tests erhalten wir ein Verhalten, was nicht in jedem Fall gewünscht ist. Zunächst einmal werden alles Tests der Oberklasse ebenfalls ausgeführt. Des Weiteren haben wir keine Möglichkeit z.B. nur die before() Logik zu nutzen, ohne ebenfalls die Logik innerhalb der after() Methode auszuführen. Das Schränkt die Wiederverwendbarkeit stark ein und führt zu unübersichtlichen Klassenhierarchien.

Die Lösung: JUnit Rules

Mit Hilfe von JUnit Rules lässt sich das Problem elegent lösen. Die Rules stellen einen mit Interceptoren oder Aspekten vergleichbaren Mechanismus bereit unabhängig von der Klassenhierarchie zusätzliche Logik in den Testablauf einzubauen.

Wie funktioniert es? 

Um eine Rule zu definieren muss eine Klasse erstellt werden, die das Interface org.junit.rules.TestRule implementiert. Darin ist nur die Methode apply(Statement base, Description description) definiert. Hinter dem Statement-Objekt verbirgt sich der laufende JUnit Test welcher mit base.evaluate() ausgeführt werden kann. Davor und danach kann eigene Logik ausgeführt werden. Dies könnte z.B. wie folgt aussehen:

Um die Rule im eigenen JUnit Test verwenden zu können wird diese einfach als Klassenvariable instanziiert und mit der @Rule Annotation versehen:
Das Ergebnis des Tests sieht wie folgt aus:

vor dem Test...
test
nach dem Test...


Die Rule wird beim Aufruf jeder einzelner Test-Methode verwendet, analog zu @Before bzw. @After. Alternativ lässt sich die Rule einmalig für die Testklasse verwenden, hierfür ist nur die folgende Änderung notwendig:

JUnit bringt bereits einige vorgefertigte Rules mit, siehe https://github.com/junit-team/junit/wiki/Rules

Freitag, 4. Oktober 2013

Excel generieren leicht gemacht

Wer schon einmal Apache POI zur Generierung von Excel Dokumenten verwendet hat, kennt wahrscheinlich Code, der so ähnlich aussieht wie der Folgende:


Man muss also relativ viel Code schreiben um ein sehr simples Dokument zu generieren. Auch die Wartbarkeit ist nicht ganz so dolle. Jede noch so kleine Änderung sorgt dafür, dass der Code angepasst werden muss. Wenn dann noch viel mit CellStyles gearbeitet wird, hört es irgendwann ganz auf.


Vor einiger Zeit wurde mir von dem Framework jXLS erzählt, mit dem sich Excel Dokumente deutlich einfacher generieren lassen.
Javaseitig ist für das gleiche Beispiel wie oben nur noch folgender Code notwendig:


Zusätlich wird noch ein Template benötigt. Das Template ist einfach eine Excel Datei, im Beispiel shopping-list.xls. Dem Template wird eine Map übergeben. In der Map befinden sich die Objekte an denen die Informationen abgefragt werden können, die in dem Excel Dokument dargestellt werden sollen.
Das Template sieht folgendermaßen aus:



Über Expression Language kann nun auf alle Objekte zugegriffen werden, die in der Map gespeichert und an das Template übergeben wurden. Es ist möglich über Listen zu itererieren und Informationen ein- bzw. auszublenden. Hintergrundfarben, Schriftarten, -größen etc. können im Template gepflegt werden und werden dann in das generierte Dokument übernommen.
So lange sich die darzustellenden Informationen nicht ändern, sondern nur die Art und Weise wie die Daten angezeigt werden sollen, muss nur das Template angepasst werden.
Das fertige Dokument sieht das folgendermaßen aus:


Weitere Informationen findet ihr hier: http://jxls.sourceforge.net/

Der Beispielcode befindet sich hier: https://github.com/gossie/jxls-demo