Erste Schritte

Author: Dan Allen Translators: Markus Eisele, Bennet Schulz Language:
Tags: cdi, weld, maven, forge, eclipse Last Update:Jul 26, 2016

Dieser Guide stellt Arquillian vor. Nach dem Lesen dieses Guides kannst Du:

  • Arquillian zu einem Maven basierten Projekt hinzufügen
  • einen Arquillian Testcase schreiben der das Verhalten eines CDI (Context and Dependency Injection) Beans überprüft.
  • den Arquillian Testcase in verschiedenen Containern ausführen.

Du wirst all dies lernen indem du Arquillian als Testsuite zu einem Java EE basierten Maven Projekt hinzufügst. Wir haben diesen Guide so entworfen,
dass du ihn schnell durcharbeiten und sofort starten kannst!

Annahmen

Der einfachste Weg, mit Arquillian anzufangen ist, wenn man es in ein Projekt integriert welches bereits Abhängigkeitsmanagement (Dependency Management) unterstützt. Das am weitesten Verbreitete Werkzeug dieser Kategorie heutzutage ist Apache Maven. Dieser Guide führt Dich zu Deiner ersten green bar (grüner Testbalken) mithilfe eines Beispiel Maven Projekts.

Arquillian basiert nicht auf Maven oder irgendeinem anderen Build-Tool. Es funktioniert genauso gut -wenn nicht besser- wenn es in einem Projekt verwendet wird, welches einen Ant oder Gradle build einsetzt. Idealerweise sollte das Build-Werkzeug allerdings Dependency Management anbieten, da es die Integration der Arquillian Bibliotheken deutlich vereinfacht, weil diese bereits im Maven Central repository vorliegen.

Dieser Guide setzt voraus, dass bei Dir Maven installiert ist. Entweder als Kommando-Zeilen Werkzeug oder in Deiner IDE (Integrated Development Environment). Wenn nicht, bitte installiere Maven jetzt. Du wirst auch ein JDK auf Deinem Rechner benötigen.

Erstelle ein neues Projekt

Es gibt zwei von uns empfohlene Wege ein neues Maven Projekt zu erstellen:

  1. Erstelle ein Projekt von einem Maven archetype
  2. Erstelle und passe ein Projekt mit JBoss Forge an

Die Verwendung von JBoss Forge stellt den mit Abstand einfacheren Weg dar. Dieser Guide bietet dir allerdings beide Alternativen an, für den Fall dass du noch nicht bereit bist JBoss Forge einzusetzen. Wähle eine der obigen Optionen um zur jeweiligen Anleitung zu springen.

Wenn Du bereits ein Maven basiertes Projekt hast, kannst Du diese Sektion als Referenz verwenden um sicherzustellen, dass Du die richtigen Abhängigkeiten im Projekt hast bevor Du weitermachst.

Erstelle ein Projekt von einem Maven Archetype

Zuerst erstelle ein Maven basiertes Java Projekt mithilfe der Kommando-Zeile unten.

$ mvn archetype:generate -DarchetypeGroupId=net.avh4.mvn.archetype \
-DarchetypeArtifactId=java-1.6-archetype

Kopiere den Text nach dem $ und füge ihn in deine Kommando-Zeilen-Fenster ein. Füge, wenn Du dazu aufgefordert wirst die in der folgen Liste stehenden Werte ein und bestätige sie mit <ENTER>.

Define value for property 'groupId': : org.arquillian.example <ENTER>
Define value for property 'artifactId': : arquillian-tutorial <ENTER>
Define value for property 'version': : <ENTER>
Define value for property 'package': : <ENTER>
Confirm properties configuration:
groupId: org.arquillian.example
artifactId: arquillian-tutorial
version: 1.0-SNAPSHOT
package: org.arquillian.example
Y: : <ENTER>

Dieses Kommando erzeugt ein Maven basiertes Java Projekt innerhalb eines Verzeichnisses mit dem Namen arquillian-tutorial unterhalb des aktuellen Verzeichnisses. Die Dateistruktur des Projekt ist wie folgt:

  • src/
    • main/
      • java/ – Hier kommen alle Java Source Dateien hin (in Java Packages)
      • resources/ – Hier kommen alle Konfigurationsdateien der Anwendung hin.
    • test/
      • java/ – Hier kommen alle Test Java Source Dateien hin (in Java Packages)
      • resources/ – Hier kommen alle Konfigurationsdateien der für die Tests hin, (beispielsweise: arquillian.xml)
  • pom.xml – Die Maven Build Datei, welche Maven sagt, wie das Projekt zu bauen ist.

Das erzeugte Projekt ist mit Java 1.6 und JUnit 4.8 vorkonfiguriert. Dies sind die im Minimum benötigten Versionen von Java und JUnit um Arquillian zu nutzen.

Der Generator hat auch ein Java Package mit dem Namen org.arquillian.example unterhalb der beiden java Verzeichnisse erstellt. Dorthin solltest Du auch Deine Java Sourcen packen und nicht direkt in das Root der java Verzeichnisse.

Arquillian unterstützt auch TestNG 5. Dennoch verwendet dieser Guide JUnit als Beispiel.

Öffnet als nächstes das pom.xml in Deiner IDE oder einem Editor. Du solltest eine XML Datei mit den basis Projekt Informationen, einer <build> und einer <dependencies> section sehen. Du kannst alle <dependency> Elemente unterhalb der JUnit Abhängigkeit entfernen. Sie werden nicht benötigt.

Wenn Du fertig bist, sollte das Ergebnis ungefähr so aussehen (Abgekürzt zur besseren Lesbarkeit):

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.arquillian.example</groupId>
    <artifactId>arquillian-tutorial</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>arquillian-tutorial</name>
    <url>http://arquillian.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Wir werden Java EE 7 Komponenten schreiben. Daher benötigst Du außerdem die Java EE 6 API als abhängige Bibliothek im Classpath um diese kompilieren zu können.

Öffne erneut die pom.xml Datei und füge das folgende XML Fragment direkt innerhalb der umschließenden <dependencies> Elemente ein. Das sollte dann so aussehen, wenn Du fertig bist:

pom.xml
<!-- clip -->
<dependencies>
    <dependency>
        <groupId>org.jboss.spec</groupId>
        <artifactId>jboss-javaee-6.0</artifactId>
        <version>1.0.0.Final</version>
        <type>pom</type>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>
<!-- clip -->

Wir empfehlen dringend, dass Du die Java EE API Artefakte mit der groupId javax:javaee-api nicht verwendest. Diese Bibliothek enthält Klassen mit verkürzten Methoden, welche dazu führen können, dass bei der Ausführung der Anwendung oder der Tests komische Absent Code Errors erscheinen sobald sich diese Klassen im Classpath befinden. Mehr dazu in dieser FaQ .

Die Grundlagen für Dein Projekt sind jetzt fertig! Überspringe den nächsten Abschnitt und gehe direkt zu Projekt in Eclipse öffnen damit wir endlich Code schreiben können!

Erstelle und passe ein Projekt mit JBoss Forge an

JBoss Forge ist ein Kommando-Zeilen Werkzeug zum Rapid-Application Development in einer auf Standards basierenden Umgebung. Gerne auch als “Maven Archetypes on steroids” bezeichnet.

Forge ist schnell installiert und dieser Guide führt Dich durch die Grundlagen. Folge einfach diesen einfachen Schritten um es zu installieren:

  1. Download Forge und packe Forge in ein beliebiges Verzeichnis auf Deiner Festplatte aus. Diese nennen wir $FORGE_HOME
    Wir gehen davon aus, dass Du die Distribution in ein Verzeichnis mit dem Namen forge in Deinem Home Verzeichnis ausgepackt hast.
  1. Füge $FORGE_HOME/bin zu Deinem Pfad hinzu (Windows, Linux oder Mac OSX)

Auf Unix basierenden Systemen bedeutet dies, dass Du $HOME/.bashrc or $HOME/.profile editieren musst. Eine entsprechende Ergänzung sieht dann beispielsweise so aus:

$ export FORGE_HOME=$HOME/forge/
$ export PATH=$PATH:$FORGE_HOME/bin

Unter Windows kann dies über die Systemeigenschaften eingestellt werden. Dorthin gelangst Du mit einem Rechts-Klick auf die “Systemsteuerung”, dann Klick auf “System Eigenschaften”, dort der Tab Reiter “Erweitert”. Ein Klick auf “Umgebungsvariablen” ermöglicht das Hinzufügen der beiden Einträge. Es wird empfohlen die Einträge als Nutzer Variablen vorzunehmen. System Variablen ist nur sinnvoll, wenn Forge in einem Verzeichnis installiert ist, welches von allen Systembenutzern gelesen werden kann.

Nachdem Forge installiert (bzw. entpackt) wurde öffne die Kommandozeile und führe das folgende forge Kommando aus:

$ forge
   _____                    
  |  ___|__  _ __ __ _  ___ 
  | |_ / _ \| `__/ _` |/ _ \  \\
  |  _| (_) | | | (_| |  __/  //
  |_|  \___/|_|  \__, |\___| 
                  |___/      
 
[no project] ~ $

Das war es schon! Forge läuft und es wird Zeit, dass Projekt zu erstellen.

Tippe das folgende Kommando innerhalb der Forge shell. Es erzeugt ein leeres Projekt in etwa der Art wie es der Maven Archetype auch getan hat:

$ project-new --named arquillian-tutorial --topLevelPackage org.arquillian.example

Dieses Kommando erzeugt ein Maven basiertes Java Projekt innerhalb eines arquillian-tutorial genannten Verzeichnisses direkt unterhalb des aktuellen Verzeichnisses.

Die Dateistruktur ist dabei wie folgt erzeugt worden:

  • src/
    • main/
      • java/ – Hier kommen alle Java Source Dateien hin (in Java Packages)
      • resources/ – Hier kommen alle Konfigurationsdateien der Anwendung hin.
        • META-INF/
          • forge.xml – Eine leere Forge Settings Datei
    • test/
      • java/ – Hier kommen alle Java Test Source Dateien hin (in Java Packages)
      • resources/ – Hier kommen alle Konfigurationsdateien der für die Tests hin, (beispielsweise: arquillian.xml)
  • pom.xml – Die Maven Build Datei, welche Maven sagt, wie das Projekt zu bauen ist.

Forge wechselt automatisch in das erstellte Projektverzeichnis.

[arquillian-tutorial] arquillian-tutorial $ 

Standardmäßig erstellt Forge Projekte, welche Java 1.6 verwenden. Das passt sehr gut, da dies auch die Minimalanforderung von Arquillian an die Projekte ist.

Nun müssen die Java EE 6 APIs hinzugefügt werden. Das wird mit dem project add-dependency Kommando gemacht:

$ project-add-dependencies org.jboss.spec:jboss-javaee-6.0:1.0.0.Final:pom:provided

Dann fehlt noch JUnit 4.8 für die Tests, als weitere Minimalanforderung von Arquillian.

$ project-add-dependencies junit:junit:4.8.1:test

Im Ergebnis sieht die von Forge erzeugte pom.xml dann so aus:

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xsi:schemaLocation="
        http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.arquillian.example</groupId>
    <artifactId>arquillian-tutorial</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.jboss.spec</groupId>
            <artifactId>jboss-javaee-6.0</artifactId>
            <version>1.0.0.Final</version>
            <type>provided</type>
            <scope>pom</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <repositories>
      <repository>
          <id>JBOSS_NEXUS</id>
          <url>http://repository.jboss.org/nexus/content/groups/public</url>
      </repository>
    </repositories>
    <build>
        <finalName>arquillian-tutorial</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Arquillian kann über das Maven Central Repository bezogen werden. Daher ist der Verweis auf das JBoss Public Repository in der pom.xml überflüssig und kann entfernt werden. Behalte aber im Hinterkopf, dass es durchaus abhängige Bibliotheken von JBoss gibt, welche nicht über Maven Central bezogen werden können.

Wenn Du zu den Anhängern gehörst, welche das Hinzufügen von Repositories in Projekt pom.xml für ein Anti-Pattern halten, dann lies diese Anweisungen um die Repositories global in der Maven settings.xml Datei einzustellen.

Die Grundlagen für Dein Projekt sind jetzt fertig! Öffne das Projekt in Eclipse, damit wir endlich Code schreiben können!

Projekt in Eclipse öffnen

Beim Entwickeln eines Java Projektes wirst Du vermutlich eine IDE, beispielsweise Eclipse, verwenden. Daher wurde Arquillian auch IDE-freundlich konzipiert. Das bedeutet, dass Arquillian Tests aus der IDE ohne besondere Änderungen ausführbar sind. Darum starten wir auch gleich mit der IDE:

Starte Eclipse. Da dies ein Maven basiertes Projekt ist, benötigst Du die Maven Integration for Eclipse auch m2e Plugin genannt um das Projekt zu öffnen. Hast Du diese nicht bereits installiert, kannst Du auch einfach die JBoss Tools installieren. Sie enthalten bereits die Maven Integration. Die folgenden Schritte beschreiben die Installation direkt über den Eclipse Marketplace (eine Art AppStore für Eclipse Plugins).

  1. Wähle das Menü Hilfe > Eclipse Marketplace... vom Hauptmenü
  2. Tippe “jboss tools” in das Eingabefeld (ohne Anführungszeichen) und drücke <ENTER>
  3. Klicke auf den “Installieren” Knopf neben dem Ergebnis “JBoss Tools (Indigo)”
  4. Beende den Install Wizard und starte Eclipse neu, wenn Du dazu aufgefordert wirst.

Bei den JBoss Tools handelt es sich um ein leichtgewichtiges Plugin, welches ein umfangreiches Set an Werkzeugen zur Entwicklung von Java EE Anwendungen, inklusive CDI Unterstützung bereitstellt. Um produktiv arbeiten zu können, empfehlen wir es daher, dieses Plugin zu verwenden.

Wenn du darauf allerdings verzichten möchtest und lieber nur die Maven Integration ohne Plugins verwenden möchtest, folge diesen einfachen Schritten:

  1. Select Help > Eclipse Marketplace... from the main menu
  2. Tippe “maven” in in das Eingabefeld (ohne Anführungszeichen) und drücke <ENTER>
  3. Klicke auf den “Installieren” Knopf neben dem Ergebnis “Maven Integration for Eclipse”
  4. Beende den Install Wizard und starte Eclipse neu wenn Du dazu aufgefordert wirst.
  5. Wiederhole die Schritte für die “Maven Integration für Eclipse WTP”

Ist das Maven Plugin installiert, kann man mit einfachen Schritten das Projekt direkt öffnen:

  1. Wähle Datei > Import... vom Hauptmenü
  2. Tippe “existing maven” in in das Eingabefeld
  3. Wähle die Option “Existing Maven Projects”, dann klicke auf den Weiter Knopf
  4. Klicke den “Durchsuchen ….” Knopf
  5. Navigiere zum Projekt Verzeichnis in Deinem Dateisystem, dann Klicke den OK Knopf.
  6. Klicke auf “Fertig” um das Projekt zu öffnen

Eclipse erkennt dann das Maven Projekt und öffnet es in der Projekt Navigator View. Wenn Du das Projekt aufklappst, sollte es folgendermaßen aussehen:

Jetzt kann es aber wirklich losgehen!

Eine Komponente erstellen

Um einen Arquillian Test schreiben zu können, benötigen wir erst einmal eine Komponente, welche es zu testen gibt. Wir fangen mit einer einfachen Komponente an, damit Du lernen kannst, wie ein einfach Arquillian Test ausgeführt wird. In den nächsten Schritten geht es zu deutlich komplexeren Szenarien.

Erstelle mithilfe Deiner IDE eine neue Java Klasse mit dem Namen Greeter im org.arquillian.example Package. Ersetze den Inhalt mit dem folgenden Code:

src/main/java/org/arquillian/example/Greeter.java
package org.arquillian.example;

import java.io.PrintStream;

/**
 * A component for creating personal greetings.
 */
public class Greeter {
    public void greet(PrintStream to, String name) {
        to.println(createGreeting(name));
    }

    public String createGreeting(String name) {
        return "Hello, " + name + "!";
    }
}

Im Test wollen wir sicherstellen, dass diese Klasse sich richtig verhält, wenn sie als CDI Bean aufgerufen wird. Natürlich könnten wir jetzt auch einen einfachen Unit-Test schreiben, aber lass uns einfach annehmen, dass diese Bean weitere Enterprise Services wie beispielsweise Dependency Injection und Messaging nutzt und in einem Container ausgeführt werden muss. (Und außerdem hat es so Raum zu wachsen ~;))

Um diese Klasse als CDI Bean zu benutzen injizieren wir sie mithilfe der @Inject Annotation in den Test. Das schreit doch geradezu nach einem Arquillian Test! Nun wird es also Zeit, die Arquillian API zum Projekt hinzu zu fügen!

Arquillian APIs hinzufügen

Öffne die pom.xml ein weiteres Mal im Editor. (Erinnerung: Sie liegt im root Verzeichnis Deines Projektes). Jetzt muss Maven wissen, welche Version der Abhängigkeiten es verwenden soll. Dazu wird das folgende XML Fragment direkt oberhalb des <build> Elements eingefügt um den sogenannten BOM bzw. die Versions-Matrix für alle transitiven Abhängigkeiten von Arquillian zu importieren.

pom.xml
<!-- clip -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.jboss.arquillian</groupId>
            <artifactId>arquillian-bom</artifactId>
            <version>#{site.components['arquillian-core'].latest_version}</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>
<!-- clip -->

Nun muss die Arquillian JUnit Integration als Abhängigkeit ergänzt werden. Dazu gehört dieses XML Fragment unter das letzte geschlossene <dependency> element:

pom.xml
<!-- clip -->
<dependency>
    <groupId>org.jboss.arquillian.junit</groupId>
    <artifactId>arquillian-junit-container</artifactId>
    <scope>test</scope>
</dependency>
<!-- clip -->

Die Arquillian JUnit Integration fügt auch die Arquillian und die ShrinkWrap APIs zum Test Classpath hinzu. Alle diese Bibliotheken werden benötigt, um einen Arquillian Test schreiben und kompilieren zu können.

Um statt JUnit TestNG zu verwenden, muss die Arquillian JUnit Integration mit der Arquillian TestNG Integration ersetzt werden.

Wenn Du Probleme mit dem bisher erstellen pom.xml hast, dann kannst Du eine komplette Version von diesem gist herunterladen.

Jetzt ist alles vorbereitet um Deinen ersten Arquillian Test zu schreiben!

Einen Arquillian Test schreiben

Ein Arquillian Test sieht erst mal so aus wie ein herkömmlicher Unit Test. Allerdings mit etwas mehr Flair. Zurück zu Deiner IDE:

Wenn Du die Meldung “Project configuration is out of date with pom.xml” erhälst, dann klicke rechts auf das Projekt und wähle Project > Maven > Update Project Configuration um das Projekt neu zu synchronisieren.

Starten wir mit dem Erstellen eines neuen JUnit Testfalls mit dem Namen GreeterTest im Verzeichnis src/test/java unterhalt des org.arquillian.example Packages. Du wirst die typischen setUp() und tearDown() Methoden nicht benötigen, da Arquillian das meiste der harten Arbeit für Dich übernimmt. Das hier haben wir bisher:

src/test/java/org/arquillian/example/GreeterTest.java
package org.arquillian.example;

import org.junit.Assert;
import org.junit.Test;

public class GreeterTest {
    @Test
    public void should_create_greeting() {
        Assert.fail("Not yet implemented");
    }
}

Nun zum Flair. Ein Arquillian Testfall muss drei Dinge beinhalten:

  1. Die @RunWith(Arquillian.class) Annotation an der Klasse
  2. Eine statische Methode annotiert mit @Deployment, welche ein ShrinkWrap Archive zurückgibt
  3. Und mindestens eine Methode, welche mit @Test annotiert ist

Die @RunWith Annotation sagt JUnit, dass es den Arquillian Test Controller verwenden soll. Arquillian schaut dann nach der statischen Methode mit der @Deployment Annotation und empfängt das Test Archiv (auch micro-deployment genannt). Dann passiert ein gewisses Maß an Magie und jede mit @Test annotierte Methode wird innerhalb der Container Umgebung ausgeführt.

Was genau ist ein Test Archiv?

Der Zweck eines Test Archivs ist die Isolation von Klassen und Ressourcen welche für den Test benötigt werden von dem Rest des Classpath. Im Gegensatz zu einem normalen Unit Testfall, bindet sich Arquillian nicht einfach in den kompletten Classpath ein. Im Gegenteil, Du fügst lediglich die Teile hinzu, welche auch vom Test benötigt werden (Das kann der komplette Classpath sein, aber das entscheidest nur Du). Das Archiv wird per ShrinkWrap definiert. Das ist eine Java API zur Erzeugung von Archiven (beispielsweise jar, war, ear). Die micro-deployment Strategie erlaubt es Dir, Dich auf die eigentlichen Testklassen zu fokussieren. Im Ergebnis führt das zu sehr schlanken Testklassen.

ShrinkWrap unterstützt auch das Auffinden von Artefakten (Bibliotheken) und das programmatische Erstellen von Konfigurationsdateien, welche ebenfalls im Test Archiv verpackt werden können. Für eine gründlichere Einführung in ShrinkWrap empfiehlt sich der ShrinkWrap introduction guide.

Fügen wir das Arquillian Flair dem Test hinzu:

src/test/java/org/arquillian/example/GreeterTest.java
package org.arquillian.example;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
public class GreeterTest {

    @Deployment
    public static JavaArchive createDeployment() {
        return ShrinkWrap.create(JavaArchive.class)
            .addClass(Greeter.class)
            .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    @Test
    public void should_create_greeting() {
        Assert.fail("Not yet implemented");
    }
}

Mithilfe von ShrinkWrap haben wir ein Java Archiv (jar) als Deployment Artefakt definiert. Es enthält die zu testende Greeter Klasse und eine leere beans.xml Datei welche als Ressource im META-INF Verzeichnis liegen soll. Mit diesem Trick aktivieren wir die CDI Funktionen für dieses Archiv.

Alles was nun noch zu tun bleibt ist, die Greeter Instanz in ein Feld direkt oberhalb der Test Methode zu injizieren und die bisher nicht implementierte Test Methode mit einem Assert auf das Verhalten des Beans auszuprogrammieren.
Um Dir ein warmes und wohliges Gefühl zu vermitteln, werden wir auch die Begrüßung auf der Konsole ausgeben.

src/test/java/org/arquillian/example/GreeterTest.java
// clip
import javax.inject.Inject;
// clip

@Inject
Greeter greeter;

@Test
public void should_create_greeting() {
    Assert.assertEquals("Hello, Earthling!",
        greeter.createGreeting("Earthling"));
    greeter.greet(System.out, "Earthling");
}

Und so sieht dann der fertige Test aus:

src/test/java/org/arquillian/example/GreeterTest.java
package org.arquillian.example;

import javax.inject.Inject;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.Test;
import org.junit.Assert;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
public class GreeterTest {

    @Deployment
    public static JavaArchive createDeployment() {
        return ShrinkWrap.create(JavaArchive.class)
            .addClass(Greeter.class)
            .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    @Inject
    Greeter greeter;

    @Test
    public void should_create_greeting() {
        Assert.assertEquals("Hello, Earthling!",
            greeter.createGreeting("Earthling"));
        greeter.greet(System.out, "Earthling");
    }
}

Glückwunsch! Damit hast Du gerade Deinen ersten Arquillian Test geschrieben!

Ahhh. Aber Du wunderst Dich vielleicht darüber, wie Du Ihn ausführen sollst? ~:S Wenn Du denkst, “Einfach wie einen JUnit Test”, liegst Du genau richtig! Dennoch müssen wir zuerst einen Container Adapter zum Classpath hinzufügen.

Einen Container Adapter hinzufügen

Wir haben eine Menge über Tests innerhalb irgendeines Containers gesprochen. Bisher aber nicht gesagt, welchen Container wir verwenden. Das liegt daran, dass es eine Laufzeitentscheidung ist.

Arquillian wählt den Ziel-Container auf der Grundlage des im Classpath verfügbaren Container Adapters aus. Das bedeutet, dass wir weitere Bibliotheken zum Projekt hinzufügen werden.

Ein Arquillian Test kann in allen Containern ausgeführt werden, welche mit dem Programmiermodell des Tests kompatibel sind und Arquillian einen entsprechenden Container Adapter bereitstellt. Der bisherige Test verwendet das CDI Programmiermodell; wir benötigen also einen Container, welcher dieses unterstützt. Wir wollen einen schnellen Roundtrip und starten daher mit dem Weld EE embedded Container.

Öffne wieder die Projektkonfiguration pom.xml und füge die folgende Gruppe von Abhängigkeiten unterhalb des letzten, schließenden <dependency> Elements hinzu:

pom.xml
<!-- clip -->
<dependency>
    <groupId>org.jboss.arquillian.container</groupId>
    <artifactId>arquillian-weld-ee-embedded-1.1</artifactId>
    <version>1.0.0.CR9</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.jboss.weld</groupId>
    <artifactId>weld-core</artifactId>
    <version>2.3.5.Final</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.6.4</version>
    <scope>test</scope>
</dependency>
<!-- clip -->

Zusammenfassend benötigst Du diese drei Bibliotheken um Arquillian mit JUnit zu verwenden:

  1. Die Arquillian JUnit Integration
  2. Einen Arquillian Container Adapter für den gewünschten Ziel-Container
  3. Die Container Laufzeit (für einen embedded container) oder einen Container Client (für einen remote container)

Wir verwenden einen sogenannten “embedded Container” in diesem Beispiel. Das bedeutet wir benötigen die Container Laufzeitumgebung: Also Weld.

Aber zurück zum Test.

Den Arquillian Test ausführen

Sind alle notwendigen Abhängigkeiten bzw. Bibliotheken dem Classpath hinzugefügt, kann der Arquillian Test genau wie ein Unit test ausgeführt werden. Egal ob durch die IDE oder das build script oder andere Build Plugins. Wir führen den Beispiel Test in Eclipse aus.

Im IDE Fenster klicke mit der rechten Maustaste auf die GreeterTest.java Datei im Eclipse Package Explorer (oder im Editor) und wähle “Run As > JUnit Test” aus dem Kontextmenü.

Bei der Ausführung des Tests solltest Du die folgende Ausgabe auf der Konsole sehen:

21 [main] INFO org.jboss.weld.Version - WELD-000900 2.3.5 (Final)
Hello, Earthling!

Dann sollte die JUnit View erscheinen und eine green bar anzeigen!

Auch direkt über Maven von der Kommandozeile kann der Test ausgeführt werden:

$ mvn test

Die nachfolgende Ausgabe sollte dabei auf der Konsole erscheinen:

-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running org.arquillian.example.GreeterTest
19 [main] INFO org.jboss.weld.Version - WELD-000900 2.3.5 (Final)
Hello, Earthling!
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.907 sec

Herzlichen Glückwunsch! Du hast Dir grade Deine erste green bar mit Arquillian verdient!

Genauer Hingeschaut!

Wie kannst Du wissen, dass CDI wirklich funktioniert? Nach allem was Du weißt hat Arquillian eine neue Instanz der Greeter Klasse erzeugt und in den Test ohne weitere Beteiligung von CDI injiziert. Lass uns beweisen, dass sie wirklich da ist.

Erstelle eine neue CDI Bean mit dem Namen PhraseBuilder im org.arquillian.example Package. Diese soll Sätze aus Vorlagen erstellen können.

src/main/java/org/arquillian/example/PhraseBuilder.java
package org.arquillian.example;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;

public class PhraseBuilder {
    private Map<String, String> templates;

    public String buildPhrase(String id, Object... args) {
        return MessageFormat.format(templates.get(id), args);
    }

    @PostConstruct
    public void initialize() {
        templates = new HashMap<String, String>();
        templates.put("hello", "Hello, {0}!");
    }
}

Öffne nun die Greeter Klasse und erstelle einen neuen Constructor welcher eine PhraseBuilder Instanz über Constructor Injection erzeugt. Dann delegiere die Erzeugung der Begrüßung an die injizierte Bean.

src/main/java/org/arquillian/example/Greeter.java
package org.arquillian.example;

import java.io.PrintStream;
import javax.inject.Inject;

public class Greeter {

    private PhraseBuilder phraseBuilder;

    @Inject
    public Greeter(PhraseBuilder phraseBuilder) {
        this.phraseBuilder = phraseBuilder;
    }

    public void greet(PrintStream to, String name) {
        to.println(createGreeting(name));
    }

    public String createGreeting(String name) {
        return phraseBuilder.buildPhrase("hello", name);
    }
}

Damit der Test wirklich funktioniert, muss jetzt also eine Instanz der Klasse PhraseBuilder erstellt werden, seine @PostConstruct Methode ausgeführt und in den Constructor der Greeter Instanz injiziert werden, sobald eine Greeter Instanz erzeugt wird. Wir können sicher sein, dass CDI am Werk ist, wenn all dies zusammenspielt.

Ein letzter Schritt: Da wir eine neue Klasse erstellt haben, müssen wir zuerst sicherstellen, dass diese in der @Deployment Methode vom Test dem Archiv hinzugefügt wird. Dazu verändern wir einfach die folgende Zeile von:

.addClass(Greeter.class)

…nach:

.addClasses(Greeter.class, PhraseBuilder.class)

Lass den Test erneut ablaufen. Du solltest erneut eine green bar! sehen! Fühlt sich gut an, nicht wahr?

Den Test Debuggen

Das wird ein kurzes Kapitel. Warum? Weil Arquillian Tests so unkompliziert sind, dass Du sie genauso wie alle anderen Unit Tests debuggen kannst. Füge einfach irgendwo einen Breakpoint hinzu (entweder im Test-Code oder im Anwendungs-Code) und klicke mit der rechten Maustaste oder im Editor auf den Test und wähle “Debug As > JUnit Test”. Jetzt debuggst Du im Container!

Wenn Du einen Remote Container verwendest funktioniert das so nicht. Stattdessen muss der Container im Debug Mode gestartet und der Debugger angehängt werden. Der Test läuft dann nämlich in einer anderen JVM als der eigentliche Code.

Du hast grade erlebt, dass Arquillian das ideale Werkzeug für das Testen von CDI Anwendungen ist. Es kümmert sich um das Laden der CDI Umgebung und injiziert die Beans direkt in den Testfall. Das Beste daran ist, dass bei der Verwendung des embedded CDI Containers die Tests genauso schnell ablaufen als bei einem einfachen Unit Test. Wenn das alles ist, was Du benötigst kannst Du den Guide jetzt zu machen und anfangen Tests zu erstellen.

Aber! Erzählt uns der Embedded Container die gesamte Geschichte? Wird die Komponente funktionieren, wenn diese in einem echten Container ausgeführt wird?

Einer der Vorteile von Arquillian ist, dass der gleiche Test in verschiedenen kompatiblen Containern ausgeführt werden kann. Egal ob Embedded oder Remote. Wenn Du daran denkst, mehrere Container zu verwenden, lies einfach weiter.

Weitere Container hinzufügen

Wie Du weißt, wählt Arquillian den Container auf Grund des verfügbaren Adapters im Classpath. Um zu einem anderen Container zu wechseln, wechsele einfach den Container Adapter vor dem Ausführen der Tests.

Zu einer bestimmten Zeit darf immer nur ein Container Adapter im Classpath sein!

Ein Weg die Bibliotheken (Adapter) im Classpath zu wechseln ist es, die Abhängigkeiten in der pom.xml jedes Mal manuell zu ändern. Aber es gibt einen viel besseren Weg.

Wir können die sogenannten Maven Profile verwenden um die Abhängigkeiten in Gruppen zu verteilen. Eine Gruppe/Profil für jeden Container Adapter und die zugehörigen, weiteren Abhängigkeiten. Zur Test Durchführung muss dann lediglich die richtige Gruppe bzw. das richtige Profil per Kommandozeilen Parameter (-P) oder die Voreinstellung in der IDE gewechselt werden.

Öffne die pom.xml Datei und erstelle ein neues Maven Profil für den Weld EE Embedded Container durch das Einfügen der folgenden Zeilen direkt unterhalb des schließenden <dependencies> Element.

pom.xml
<!-- clip -->
<profiles>
    <profile>
        <id>arquillian-weld-ee-embedded</id>
        <dependencies>
            <dependency>
                <groupId>org.jboss.spec</groupId>
                <artifactId>jboss-javaee-6.0</artifactId>
                <version>1.0.0.Final</version>
                <type>pom</type>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.jboss.arquillian.container</groupId>
                <artifactId>arquillian-weld-ee-embedded-1.1</artifactId>
                <version>1.0.0.CR9</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.jboss.weld</groupId>
                <artifactId>weld-core</artifactId>
                <version>2.3.5.Final</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-simple</artifactId>
                <version>1.6.4</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </profile>
</profiles>
<!-- clip -->

Als nächstes entfernst Du die jboss-javaee-6.0 und die Weld EE Container Adapter Abhängigkeiten aus der Hauptsektion der <dependencies>. Das sollte dann so aussehen, wenn Du fertig bist:

pom.xml
<!-- clip -->
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.jboss.arquillian.junit</groupId>
        <artifactId>arquillian-junit-container</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
<profiles>
    <profile>
        <id>arquillian-weld-ee-embedded</id>
        <dependencies>
            <dependency>
                <groupId>org.jboss.spec</groupId>
                <artifactId>jboss-javaee-6.0</artifactId>
                <version>1.0.0.Final</version>
                <type>pom</type>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.jboss.arquillian.container</groupId>
                <artifactId>arquillian-weld-ee-embedded-1.1</artifactId>
                <version>1.0.0.CR9</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.jboss.weld</groupId>
                <artifactId>weld-core</artifactId>
                <version>2.3.5.Final</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-simple</artifactId>
                <version>1.6.4</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </profile>
</profiles>
<!-- clip -->

Die Java EE API Abhängigkeit ist ebenfalls in das Container Adapter Profil gewandert, da manche Container wie beispielsweise der Embedded GlassFish diese bereits mitbringen. Beide im Classpath zu haben würde zu Problemen führen. Darum dieser Tanz mit dem Classpath.

Jetzt fügen wir zwei weitere Profile in die pom.xml Datei innerhalb des <profiles> Elements ein. Zuerst für den Embedded GlassFish:

pom.xml
<!-- clip -->
<profile>
    <id>arquillian-glassfish-embedded</id>
    <dependencies>
        <dependency>
            <groupId>org.jboss.arquillian.container</groupId>
            <artifactId>arquillian-glassfish-embedded-3.1</artifactId>
            <version>1.0.0.CR4</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.glassfish.main.extras</groupId>
            <artifactId>glassfish-embedded-all</artifactId>
            <version>3.1.2</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</profile>
<!-- clip -->

und das andere Profil für den JBoss AS managed:

pom.xml
<!-- clip -->
<profile>
    <id>arquillian-jbossas-managed</id>
    <dependencies>
        <dependency>
            <groupId>org.jboss.spec</groupId>
            <artifactId>jboss-javaee-6.0</artifactId>
            <version>1.0.0.Final</version>
            <type>pom</type>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.as</groupId>
            <artifactId>jboss-as-arquillian-container-managed</artifactId>
            <version>7.1.1.Final</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</profile>
<!-- clip -->

Jetzt haben wir die Wahlmöglichkeit die Tests in einem der drei Container auszuführen.

Wenn du Probleme mit der pom.xml Datei hast, kannst Du die bisher erstelle direkt als gist datei herunterladen.

Test mit mehreren Containern

Aktualisierst Du das Projekt jetzt in Eclipse wirst Du feststellen, dass es nicht mehr gebaut wird. Das liegt daran, dass Du der IDE erst noch sagen musst, welches Maven Profil sie verwenden soll. Also aktivieren wir mal das Weld EE embedded Profil um den Ausgangszustand wiederherzustellen.

In Eclipse gibt es zwei Wege um Maven Profile zu aktivieren:

  1. Die Manuelle Konfiguration (Standard Ansatz)
  2. oder der Maven Profile Selector (durch die JBoss Tools bereitgestellt)

Aktives Maven Profil setzen: Manuelle Konfiguration

Um das aktive Maven Profil zu setzen, folge diesen Schritten:

  1. Rechts-Klick auf das Projekt und Auswahl von “Eigenschaften”
  2. Wähle den Maven Eigenschaften Reiter
  3. Gib die Profil ID in das Aktive Maven Profiles Feld ein (beispielsweise arquillian-weld-ee-embedded)
  4. Klicke auf den OK Knopf und akzeptiere die Projektänderungen

Hier ist ein Screenshot des Maven Eigenschaften Dialogs, welcher die aktivierten Profile anzeigt:

Aktives Maven Profil setzen: Maven Profile Selector

Wenn Du die JBoss Tools installiert hast, wird das Auswählen des aktiven Maven Profils noch einfacher:

  1. Rechts-Klick auf das Projekt und Auswahl von “Maven > Select Active Profiles…” (Alternativ kann dies auch per Ctrl+Shift+P oder dem Knopf aus der Toolbar erfolgen)
  2. Wähle die Box neben dem Profil welches Du aktivieren willst an. (beispielsweise arquillian-weld-ee-embedded)
  3. Klicke auf den OK Knopf.

Hier ist ein Screenshot des Maven Profil Selector Dialogs, welcher die aktivierten Profile anzeigt:

Ist das Profil einmal aktiviert, sollte der Test wieder erfolgreich ausgeführt werden können.

Du weißt schon, dass der Test im Weld EE Embedded Container funktioniert. Nun wechseln wir auf den GlassFish Embedded indem die o.g. Schritte durchgeführt werden. Diesmal aktiviere allerdings das arquillian-glassfish-embedded Profil. Führe den Test erneut aus. Du solltest auf der Konsole sehen, wie der GlassFish startet, gefolgt von einer erneuten green bar!

Du hast die Tests nun auf verschiedenen embedded Containern ausgeführt. Einem CDI Container (Weld) und einem Java EE Container (GlassFish). Bei beiden handelte es sich um Container, welche in der gleichen JVM wie die Tests laufen. Um wirklich sicher zu sein, müssen die Tests in einem alleinstehenden Container erfolgreich durchlaufen werden. Daher wechseln wir zum JBoss AS.

Um die Tests in einer alleinstehenden Instanz vom JBoss AS laufen zu lassen, muss diese erst einmal konfiguriert werden. Dies geschieht entweder:

  1. durch Herunterladen und Entpacken der Distribution an eine Stelle im Dateisystem außerhalb des Projekts oder
  2. du lässt Maven beides beim Bauen des Projekts selber machen.

Folge diesen Schritten um JBoss AS 7 außerhalb des Projekts aufzusetzen:

  1. Lade JBoss AS 7 herunter
    (Versichere Dich, dass die Version die Du auswählst genau zu der Version passt, die Du in Deinem pom.xml für <artifactId>jboss-as-arquillian-container-managed</artifactId> angegeben hast!)
  2. Packe das Archiv aus
  3. (optional) Setze die JBOSS_HOME Umgebungs-Variable auf den Pfad des ausgepackten Archivs.

Um Maven die Arbeit beim Bauen machen zu lassen, musst Du das folgenden XML Fragment unter das schließende <id> Element des arquillian-jbossas-managed Profils einfügen:

pom.xml
<!-- clip -->
<build>
    <plugins>
        <plugin>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>unpack</id>
                    <phase>process-test-classes</phase>
                    <goals>
                        <goal>unpack</goal>
                    </goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>org.jboss.as</groupId>
                                <artifactId>jboss-as-dist</artifactId>
                                <version>7.1.1.Final</version>
                                <type>zip</type>
                                <overWrite>false</overWrite>
                                <outputDirectory>target</outputDirectory>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build> 
<!-- clip -->

Die managed JBoss AS 7 Instanz benötigt ein wenig Arquillian Konfiguration. Erstelle eine Datei mit dem Namen arquillian.xml unter src/test/resources und ändere den Wert des jbossHome Propertie auf das Verzeichnis in das Du den JBoss AS 7 installiert hast. Wenn Du Maven die Arbeit beim Bauen machen lässt (maven dependency plugin) lautet der Wert target/jboss-as-7.1.1.Final.

src/test/resources/arquillian.xml
<arquillian xmlns="http://jboss.org/schema/arquillian"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://jboss.org/schema/arquillian
        http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
    <container qualifier="jbossas-managed" default="true">
        <configuration>
            <property name="jbossHome">target/jboss-as-7.1.1.Final</property>
        </configuration>
    </container>
</arquillian>

Wechsele jetzt das aktive Maven Profil auf arquillian-jbossas-managed und lass die Tests ein letztes mal laufen. Du solltest in der Konsole sehen, wie der JBoss AS 7 startet und ….. dann eine erneute green bar erscheint!

Die Meldungen von System.out werden direkt ins Server log und nicht auf die Konsole geschrieben.

Das ist der gleiche Test. Nur diesmal in einem alleinstehenden (nicht eingebetteten) Javva EE Container. Arquillian packt das Test Archiv, deployt es auf den Container als Java EE Archiv und führt den Test remote durch. Erfasst dann die Ergebnisse und stellt sie der Eclipse JUnit Ergebnis View (oder dem Maven Surefire Plugin) zur Verfügung.

Share the Knowledge

Find this guide useful?

There’s a lot more about Arquillian to cover. If you’re ready to learn more, check out the other available guides.

Feedback

Find a bug in the guide? Something missing? You can fix it by forking this website, making the correction and sending a pull request. If you’re just plain stuck, feel free to ask a question in the user discussion forum.

Recent Changelog

  • Jul 26, 2016: Updates versions of weld artifacts in getting_started document by Tomas Remes
  • Apr 26, 2016: Updated jboss forge distribution link by Bartosz Majsak
  • Jan 13, 2016: Fix typos in the german getting started guide by Bennet Schulz
  • Aug 02, 2015: Update forge commands in getting started guide (all languages) by Andrea Cosentino
  • Apr 30, 2012: Upgrade to jboss as 7.1.1.final by Dan Allen
  • Apr 19, 2012: Remove redundant metadata (internal change) by Dan Allen
  • Apr 13, 2012: Upgrade weld-ee-embedded adapter to 1.0.0.cr3 by Dan Allen
  • Apr 10, 2012: Add javax.inject.inject import by Dan Allen
  • Apr 10, 2012: Update first pom.xml listing, update download links, remove dead link and clarify java version by Dan Allen
  • Apr 05, 2012: Add reference_rev prolog field for translations by Dan Allen
  • Apr 05, 2012: Use description in prolog for guide summary by Dan Allen
  • Mar 29, 2012: Updated the versions for weld and slf4j given in the pom files from 1.1.1.final and 1.5.10 to 1.1.5.final and 1.6.4 respectively by paul-thomson
  • Mar 28, 2012: Use variable for arquillian core version by Dan Allen
  • Mar 28, 2012: Fix bom version; add missing import for @inject by Craig Schwarzwald
  • Mar 26, 2012: Escape stray inline xml tags by Dan Allen

See full history »