Oder: Arquillian, das Baldrian der Softwareentwickler?

CDI – teste, aber bitte nicht meine Nerven

Sven Ruppert
©Shutterstock.com/maximmmmum

„Unter der Annahme einer punktförmigen Kuh im Vakuum“ oder ähnlich praktisch relevant beginnt doch so mancher Vortrag/Vorlesung zum Thema TDD [1]. Nur wie kann man sich dem Thema TDD nähern, wenn man CDI verwendet?

Im letzten Artikel [2] haben wir uns mit einem kleinen Beispiel befasst, um den praktischen Einsatz von ContextResolvern mit Hilfe von CDI zu demonstrieren. Allerdings sind wir an dieser Stelle nicht auf die Möglichkeiten eingegangen, wie dieser Code getestet werden kann. Eine zentrale Frage ist also: Wie können partielle Codeteile getestet werden, die CDI verwenden? Sicherlich nicht wünschenswert ist die Notwendigkeit für jeden jUnit-Test einen JEE-Container mit allen projektspezifischen Modulen zu starten. (inkl manuellen Tests).

Die jUnit-Tests sollten so schlank wie möglich gehalten werden, um damit kurze Zyklen zwischen programmieren und testen zu gewährleisten.

Die Wurzel aller Arbeit: @Inject?

Beginnen wir mit dem einfachsten Fall, einem einfachen @Inject (Listing 1) innerhalb einer JavaBean.

private @Inject 
@CDISimpleDateFormatter(„rechnungsdatum“) 
SimpleDateFormat sdf; 


Wie kann man an der Stelle testen, ob die Anweisung (Injizieren der Instanz) korrekt ausgeführt wird? Prinzipiell sollte ein Assert.assertNotNull(sdf); hier ausreichend sein. Schon ist sichergestellt, dass es beim Zugriff auf dieses Attribut keine NullPointerException (NPE) geben wird.

@Test
public void test001() throws Exception {
   Assert.assertNotNull(sdf);
   final String format = sdf.format(new Date());
}


Listing 2a zeigt den jUnit-Test selbst, so wie es sicherlich für viele Entwickler gewohnt aussehen wird. Wo kommt nun die Instanz der Klasse SimpleDateFormat (sdf) her? Eine Idee könnte sein, dass die Methode mit der Annotation @Before verwendet werden kann, um den Container zu starten (Listing 2b). Allerdings ist dieses Vorgehen nicht sonderlich effizient. Wesentlich eleganter wäre eine Version wie in Listing 2c.

private SimpleDateFormat sdf;
private final WeldContainer weldContainer;
@Before
public void setUp() throws Exception {
   weldContainer = new Weld().initialize();
   sdf = weldContainer.instance()
      .select(SimpleDateFormat.class, 
      new AnnotationLiteral<CDISimpleDateFormatter> (){})
      .get();
}


@Inject @CDISimpleDateFormatter("rechnungsdatum")
private SimpleDateFormat sdf;

@Test
public void test001() throws Exception {
   Assert.assertNotNull(sdf);
   final String format = sdf.format(new Date());
}


Arquillian, ein kleines grünes Männchen?  

Listing 2c geht davon aus, dass die Instanz der Testklasse selbst von einem Container verwaltetet wird. Damit ist dann die Verwendung von @Inject möglich. Um das zu erreichen sind nur wenige Schritte nötig. Der erste Schritt ist, wie bei Maven-Projekten üblich, die Definition der benötigten Libs in der pom.xml. Welche für die aktuelle Version von Arquillian notwendig sind, entnimmt man am besten der Webseite [3]. Der zweite Schritt besteht darin, den Default-Runner von jUnit durch den ArquillianRunner zu ersetzen. Das geschieht mittels RunWith-Annotation der Testklassen @RunWith(Arquillian.class).

Der dritte und letzte Schritt ist die Definition des Deployments. Das Deployment stellt die Verpackung für Arquillian dar. Hier gibt es verschiedene Zielformate, die alle aus dem JEE-Umfeld kommen. Für unsere Tests reicht das JavaArchive wie in Listing 3.

@Deployment
public static JavaArchive createDeployment() {
return ShrinkWrap.create(JavaArchive.class)
   	.addPackages(true, "org.rapidpm.demo.jaxenter")
         	.addPackages(true, "junit.org.rapidpm.demo.jaxenter")
         	.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}


Hier werden alle notwendigen Klassen deklariert, die im JavaArchive vorhanden sein müssen, um den Test erfolgreich durchzuführen. Dabei ist zu beachten, dass die Test-Klassen natürlich auch dazu gehören. Nun kann der jUnit-Test ausgeführt werden.

Fazit

Arquillian ist die erste Wahl, wenn es um den Aufbau von CDI-Tests geht. In der Kürze konnte hier auf der einen Seite nur oberflächlich auf Arquillian eingegangen werden. Allerdings ist damit auch gezeigt, wie schnell die Basisinfrastruktur in Betrieb genommen werden kann. Es steht also nichts im Wege um auch beim Thema CDI mit jUnit-Tests effektiv zu arbeiten. Wer mehr über Arquillian erfahren will, sollte einen Blick auf diesen JAXenter-Artikel werfen.

In Alt-Projekten, in denen CDI auf Java-SE-Seite in Swing/JavaFX-Kombinationen eingebettet worden ist, konnten schnell und einfach vorhandene Tests angepasst werden. Damit blieb die bestehende Testabdeckung erhalten und konnte ohne semantische Brüche stetig weiterentwickelt werden.

Die Quelltexte zu diesem Text sind unter [4] zu finden. Wer umfangreichere Beispiele zu diesem Thema sehen möchte, dem empfehle einen Blick auf [5] (Modul cdi-commons).

Aufmacherbild: flat icons for web and mobile applications with beverages (flat design with long shadows) von Shutterstock / Urheberrecht: maximmmum

Geschrieben von
Sven Ruppert
Sven Ruppert
Sven Ruppert arbeitet seit 1996 mit Java und ist Developer Advocate bei Vaadin. In seiner Freizeit spricht er auf internationalen und nationalen Konferenzen, schreibt für IT-Magazine und für Tech-Portale. Twitter: @SvenRuppert
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.