Komma igång

Author: Dan Allen Translator: Tommy Tynjä Language:
Tags: cdi, weld, maven, forge, eclipse Last Update:Sep 21, 2017

Detta är en introduktionsguide till Arquillian. Efter att ha läst den här guiden kommer du att kunna:

  • Addera Arquillian till ett Maven-baserat Javaprojekt.
  • Skriva ett Arquilliantest som testar beteendet av en CDI-böna (Contexts and Dependency Injection).
  • Exekvera ditt Arquilliantest i ett flertal kompatibla containers.

Du kommer lära dig dessa kunskaper genom att lägga till Arquillian till testsviten av en Maven-baserad Java EE-applikation. Guiden har utformats kort och koncist, för att du ska kunna komma igång så snabbt som möjligt!

Antaganden

Det enklaste sättet att komma igång med Arquillian är att lägga till det till ett projekt som tillhandahåller beroendehantering, så kallad dependency management. Det mest utbredda verktyget för det idag är Apache Maven. Den här guiden kommer att lotsa dig till din första green bar (grönt test) genom att använda ett exempelprojekt baserat på Maven.

Arquillian är inte beroende av Maven eller något annat specifikt byggverktyg, utan fungerar lika bra—om inte bättre—med t.ex. Ant eller Gradle. Byggverktyget bör dock tillhandahålla dependency management då det förenklar processen med att sätta upp Arquillian och dess bibliotek, eftersom dessa distribueras via Maven Central repository.

Denna guide föresätter att du har Maven tillgängligt, antingen via en kommandotolk eller din IDE (Integrated Development Environment). Om så inte är fallet, var vänlig och installera Maven nu. Du behöver också ha JDK (Java Development Kit) 1.5 eller senare installerad på din dator.

Skapa ett nytt projekt

Det finns två rekommenderade sätt som du kan skapa ditt nya Maven-projekt på:

  1. Skapa ett nytt projekt från en Maven archetype
  2. Skapa ett nytt projekt med hjälp av JBoss Forge

JBoss Forge är det enklare tillvägagångssättet, men den här guiden kommer att visa båda alternativen ifall du inte är villig att använda JBoss Forge. Välj ett av alternativen ovan för att komma vidare till instruktionerna.

Om du redan har ett Maven-projekt tillgängligt så kan du använda den här sektionen för att kontrollera att du har satt upp Arquillian och dess beroenden på ett korrekt sätt innan du går vidare.

Skapa ett nytt projekt från en Maven archetype

Först, skapa ett Maven-baserat Java-projekt genom att använda kommandot nedan.

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

Kopiera texten efter $ och klistra in i din kommandotolk. Svara på frågorna som kommer upp genom att skriva in värdena efter de dubbla kolonen nedan. Avsluta varje rad med Enter (som indikeras av <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>

Det här kommandot kommer att generera ett nytt Maven-baserat Java-projekt i underkatalogen arquillian-tutorial. Projektets filstruktur visas nedan:

  • src/
    • main/
      • java/ – Här placeras projektets alla källkodsfiler (i Java-paket)
      • resources/ – Här placeras projektets alla konfigurationsfiler
    • test/
      • java/ – Här placeras projektets alla testklasser (i Java-paket)
      • resources/ – Här placeras projektets testkonfigurationsfiler (t.ex. arquillian.xml)
  • pom.xml – Mavens byggfil som beskriver hur projektet ska byggas.

Projektet är automatiskt konfigurerat för att använda Java 1.6 och JUnit 4.8, som är de lägsta versionerna av Java och JUnit som Arquillian stöder.

Generatorn skapar även ett Java-paket org.arquillian.example under båda java-katalogerna. Du bör placera dina källkodsfiler i detta paket, istället för direkt under rotkatalogen java.

Arquillian stöder även TestNG 5. Vi kommer dock endast att använda JUnit i denna guide.

Öppna pom.xml i valfri ordbehandlare. Du borde se en XML-fil innehållandes grundläggande projektinformation, en build- samt en dependencysektion. Du kan ta bort alla <dependency>-element under JUnit-beroendet då de inte behövs i detta fall.

Efter att ha gjort den förändringen, borde du ha en fil med följande innehåll (trimmad för ökad läsbarhet):

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>

Vi kommer att skriva Java EE 6-komponenter. Därför behöver vi också lägga till ett beroende till Java EE 6 så att vi kan kompilera dessa komponenter.

Öppna upp pom.xml-filen igen och lägg till följande XML-fragment direkt i <dependencies>-elementet. Sektionen bör nu se ut så här:

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 -->

Vi avråder dig starkt från att använda det Java EE 6 API som har koordinaterna javax:javaee-api. Den artefakten innehåller klasser som kan få din applikation att kasta märkliga fel om den lämnas på classpath (även under testkörningar). Detaljerad information om detta finns att läsa här.

Nu är grunden för ditt projekt färdigt! Hoppa vidare till sektionen Öppna projektet i Eclipse så vi kan börja skriva lite kod!

Skapa ett nytt projekt med hjälp av JBoss Forge

JBoss Forge är en kommandotolk för s.k. rapid-application development i en standardiserad miljö. Man skulle kunna kalla det för Maven Archetypes på steroider.

Att installera Forge är en relativt snabb process och den här guiden kommer att lotsa dig genom grunderna. Följ stegen nedan för att installera Forge:

  1. Ladda ner Forge och zippa upp det i en katalog på din hårddisk, vi kommer att kalla katalogen $FORGE_HOME
    Vi kommer här att förutsätta att du extraherat distributionen till en katalog forge under din hemkatalog
  2. Lägg till $FORGE_HOME/bin till din miljövariabel path (Windows, Linux eller Mac OSX)

Att lägga till Forge på path i Unixbaserade operativssytem brukar betyda editering av $HOME/.bashrc eller $HOME/.profile. Du kommer då även behöva sätta följande miljövariabler:

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

Gällande Windows kommer du att behöva högerklicka på “Kontrollpanelen”, sedan klicka “Systemegenskaper”, öppna fliken “Avancerade systeminställningar”, och sedan klicka “Miljövariabler” och lägga till dessa två variabler visuellt. Vi rekommenderar att du sätter variablerna specifikt för din användare, om du inte har packat upp Forge i en katalog där alla användare har tillgång till den.

Nu när Forge är installerat (dvs. extraherat), öppna en kommandotolk och kör följande forge-kommando:

$ forge
   _____
  |  ___|__  _ __ __ _  ___
  | |_ / _ \| `__/ _` |/ _ \  \\
  |  _| (_) | | | (_| |  __/  //
  |_|  \___/|_|  \__, |\___|
                   |___/

[no project] ~ $

Det var allt! Nu är Forge uppe och snurrar. Nu är det dags att skapa projektet.

Exekvera följande kommando i Forge-kommandotolken för att skapa ett nytt projekt, likt det som beskrevs för Maven archetype ovan:

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

Det här kommandot genererar ett nytt Maven-baserat Java-projekt i underkatalogen arquillian-tutorial.

Den filstruktur som Forge har genererat åt projektet visas nedan:

  • src/
    • main/
      • java/ – Här placeras projektets alla källkodsfiler (i Java-paket)
      • resources/ – Här placeras projektets alla konfigurationsfiler
        • META-INF/
          • forge.xml – En tom konfigurationsfil för Forge
    • test/
      • java/ – Här placeras projektets alla testklasser (i Java-paket)
      • resources/ – Här placeras projektets testkonfigurationsfiler (t.ex. arquillian.xml)
  • pom.xml – Mavens byggfil som beskriver hur projektet ska byggas.

Forge skapar också projektets katalog under den nuvarande katalogen i din Forge-kommandotolk.

[arquillian-tutorial] arquillian-tutorial $

Vi behöver nu lägga till ett Java EE API. Det gör vi genom att använda kommandot project add-dependency, se nedan:

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

Du behöver också lägga till JUnit 4.8, som är den lägsta versionen av JUnit som Arquillian stöder, som ett testberoende:

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

Resultatet av den pom.xml som Forge genererat ser ut följer:

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 distribueras via Maven Central repository, så deklarationen för JBoss Public repository i pom.xml-filen är onödig och kan därför tas bort. Det kan dock hända att du behöver den ifall du väljer att använda dig utav annan mjukvara från JBoss som inte finns tillgänglig i Maven Central.

Om du tycker att repositories som deklareras i ditt projekts pom.xml är ett s.k. antipattern, läs följande instruktioner för att lägga till repositoryt globalt i din settings.xml-fil.

Nu är grunden för ditt projekt färdigt! Nu är det dags att öppna projektet i Eclipse så att vi kan börja skriva lite kod!

Öppna projektet i Eclipse

När du utvecklar Javaprojekt så är det högst troligt att du använder dig utav en IDE, t.ex. Eclipse. Av den anledningen har Arquillian designats för att vara IDE-vänlig, vilket betyder att du kan köra dina Arquilliantest direkt från din IDE utan några okonventionella metoder. Så låt oss börja utnyttja IDEn på en gång.

Börja med att starta Eclipse. Eftersom detta är ett Maven-projekt, behöver du pluginen Maven Integration for Eclipse (m2e) installerad för att kunna öppna projektet. Om du inte redan har integrationen installerad, så är det enklaste sättet att installera JBoss Tools. Följ stegen nedan för att installera det från Eclipse Marketplace (ungefär som app store för Eclipse):

  1. Välj Help > Eclipse Marketplace... från huvudmenyn
  2. Skriv “jboss tools” i Find-rutan (utan citationstecken) och tryck Enter
  3. Klicka på Install-knappen bredvid JBoss Tools (Indigo)
  4. Slutför installationsguiden och starta sedan om Eclipse ifall du blir uppmanad till detta

JBoss Tools tillhandahåller en trevlig miljö för att utveckla Java EE-baserade applikationer, inklusive utmärkt CDI-stöd. Du behöver inte vara orolig, det är inte en stor och klumpig plug-in.

Men om du bara vill ha Maven-integrationen utan det extra stöd som JBoss Tools tillhandahåller, följ istället följande steg:

  1. Välj Help > Eclipse Marketplace... från huvudmenyn
  2. Skriv “maven” i Find-rutan (utan citationstecken) och tryck Enter
  3. Klicka på Install-knappen bredvid Maven Integration for Eclipse
  4. Slutför installationsguiden och starta sedan om Eclipse ifall du blir uppmanad till detta
  5. Återupprepa stegen för att installera Maven Integration for Eclipse WTP

När du väl har integrations-plug-in för Maven installerad, följ följande steg för att öppna projektet:

  1. Välj File > Import... från huvudmenyn
  2. Skriv “existing maven” i inmatningsfältet
  3. Välj alternativet “Existing Maven Projects”, klicka sedan på knappen Next
  4. Klicka på knappen Browse…
  5. Navigera till projektets katalog på filsystemet och klicka sedan OK
  6. Klicka på knappen Finish för att öppna projektet

Eclipse kommer att känna igen att detta är ett Maven-projekt och öppna det i vyn Project Navigator. Om du expanderar projektet så borde det se ut ungefär som på den här bilden:

Då kan vi sätta igång!

Skapa en komponent

För att skriva ett Arquilliantest, behöver vi ha en komponent att testa. Låt oss börja med att skapa en enkel komponent så att du kan lära dig hur du exekverar ett enkelt Arquilliantest utan andra distraktioner. Vi kommer stegvis att gå vidare till mer invecklade exempel.

I din IDE, skapa en ny Javaklass med namnet Greeter i paketet org.arquillian.example. Ersätt innehållet i filen med följande hälsningslogik:

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 + "!";
    }
}

Vi vill verifiera att den här klassen beter sig korrekt när den anropas som en CDI-böna (Contexts and Dependency Injection). Självklart hade vi lika gärna kunnat skriva ett enkelt enhetstest. Men låt oss låtsas som om den här bönan använder andra tjänster så som dependency injection och messaging vilket gör att den måste köras i en container. (På så sätt har vi också utrymme för att utöka testet senare ~;))

För att använda klassen som en CDI-böna behöver vi injicera (inject) den till testet med hjälp av @Inject-annotationen. Läge för ett Arquilliantest! Det betyder att det är dags att lägga till Arquillians API till projektet!

Lägga till Arquillians API

Öppna upp pom.xml-filen igen, som ligger i rotkatalogen för ditt projekt, i din ordbehandlare. Vi behöver instruera Maven om vilka versioner av artefakterna som vi vill använda. Lägg till följande XML-fragment direkt ovanför <build>-elementet för att importera BOM (Bill of Materials), eller versionmatrisen for Arquillians transitiva beroenden.

pom.xml
<!-- clip -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.jboss.arquillian</groupId>
            <artifactId>arquillian-bom</artifactId>
            <version>1.4.0.Final</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>
<!-- clip -->

Lägg sedan till följande XML-fragment direkt under det sista <dependency>-elementet för att lägga till Arquillians JUnit-integration:

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

Arquillians JUnit-integration lägger också till Arquillian och ShrinkWraps APIer till teststrukturens classpath. Du behöver dessa bibliotek för skriva och kompilera ett test baserat på Arquillian och JUnit.

För att använda TestNG istället för JUnit, byt ut Arquillians JUnit-integration mot Arquillians TestNG-integration.

Om du har problem med att sätta upp din pom.xml korrekt, kan du ladda ner filen härifrån.

Då är allt klart för ditt första Arquilliantest!

Skriva ett Arquilliantest

Ett Arquilliantest ser precis ut som ett enhetstest, fast med lite mer “känsla”. Låt oss gå tillbaka till din IDE.

Om du stöter på meddelandet “Project configuration is out of date with pom.xml”, högerklicka och välj Project > Maven > Update Project Configuration för att synkronisera Mavens inställningar med projektet.

Börja skriva ett nytt JUnit-test i src/test/java i paketet org.arquillian.example som du kallar för GreeterTest. Du behöver inte sätta upp setup- eller teardown-metoder då Arquillian sköter det mesta av det tunga arbetet. Nu har vi kommit så här långt:

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");
    }
}

Nu, gällande den där “känslan”. Ett Arquilliantest måste ha följande tre saker:

  1. En @RunWith(Arquillian.class)-annotering på klassen
  2. En statisk metod annoterad @Deployment som returnerar ett ShrinkWrap-arkiv
  3. Åtminstone en metod som är annoterad @Test

Annotationen @RunWith instruerar JUnit att använda Arquillian för att kontrollera testet. Arquillian kommer sedan att leta efter en statisk metod som är annoterad @Deployment för att hämta arkivet som ska testas (dvs. en s.k. micro-deployment). Sedan sker lite magi och varje metod annoterad med @Test kommer köras inuti själva containern.

Vad är ett testarkiv?

Syftet med ett testarkiv är att isolera klasserna och resurserna som är nödvändiga för testet från resten av projektets classpath. Till skillnad från ett vanligt enhetstest så kommer Arquillian inte att bara ta hela projektets classpath. Istället så lägger du enbart till de resurser som testet behöver (vilket förvisso kan vara hela projektets classpath om du bestämmer dig för det). Arkivet definieras med hjälp av ShrinkWrap, vilket är ett Java API för att skapa arkiv (t.ex. jar, war, ear) i Java. Tanken med micro-deployments är att låta dig fokusera på enbart de klasser som du vill testa, vilket håller dina tester enkla och lättviktiga.

ShrinkWrap stöder också möjligheten att hitta artefakter (bibliotek) och skapa konfigurationsfiler programmatiskt, vilka sedan kan läggas till i testarkivet. För en djupare introduktion till ShrinkWrap, läs introduktionen till ShrinkWrap.

Låt oss lägga till Arquilliankänslan till testet:

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");
    }
}

Genom ShrinkWrap har vi definerat att ett Java-arkiv (jar) ska driftsättas innehållandes klassen Greeter som testet kommer att kalla på, samt en tom beans.xml i META-INF-katalogen vilket behövs för att aktivera CDI-funktionaliteten.

Allt vi nu behöver göra är att injicera instansen av Greeter till ett fält direkt ovanför testmetoden och ersätta innehållet i testmetoden med något som faktiskt säkerställer bönans beteende. För att göra testet lite trevligare kommer vi också att skriva ut bönans hälsning till konsolen.

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");
}

Så här bör testet se ut när du är klar:

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");
    }
}

Du har skrivit ditt första Arquilliantest!

Nu undrar du säkert bara hur du ska köra det ~:S Om du tänker “jag kör det precis som ett enhetstest”, så har du rätt! Men först måste vi lägga till en containeradapter till classpathen.

Lägga till en containeradapter

Vi har pratat mycket om att testa i en container, men hittills har vi inte nämnt vilken. Det är för att det är ett runtimebeslut.

Arquillian väljer målcontainern baserat på vilken containeradapter som finns tillgänglig på testernas classpath. Det betyder att vi kommer lägga till fler bibliotek till projektet.

Ett Arquilliantest kan exekveras i vilken container som helst som är kompatibel med programmeringsmodellen som används i testet (och under förutsättning att den aktuella containern har en Arquillianadapter). Vårt test använder CDI’s programmeringsmodell, så vi behöver använda oss utav en container som stöder CDI. Vi vill ha en snabb utvecklingsprocess, så vi börjar med den inbäddade Weld EE containern (embedded container).

Öppna filen pom.xml återigen och lägg till följande grupp av beroenden direkt under de andra <dependency>-elementen:

pom.xml
<!-- clip -->
<dependency>
    <groupId>org.jboss.arquillian.container</groupId>
    <artifactId>arquillian-weld-ee-embedded-1.1</artifactId>
    <version>1.0.0.CR3</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.jboss.weld</groupId>
    <artifactId>weld-core</artifactId>
    <version>1.1.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 -->

För att summera, här är de tre bibliotek som du behöver för att använda Arquillian (med JUnit):

  1. Arquillians JUnit-integration
  2. En Arquillian containeradapter för den aktuella containern
  3. En container runtime (embedded container) eller en containerklient (remote container)

Vi använder oss utav en inbäddad container i det här exemplet, så vi behöver Weld, containers runtimemiljö.

Nu tillbaka till testet.

Kör Arquilliantestet

När du väl lagt till alla nödvändiga bibilotek för Arquillian på classpath, så kan du köra Arquilliantestet precis som ett enhetstest, oavsett om du kör den från din IDE, ett byggskript eller någon annan testplugin. Låt oss köra testet i Eclipse.

Från IDE-fönstret, högerklicka på filen GreeterTest.java i Package Explorer (eller i editorn) och välj Run As > JUnit Test från menyn.

När du kör testet, så bör du se följande text loggas till konsolen:

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

Du borde see JUnit-vyn dyka upp och visa en green bar!

Du kan också köra testet från kommandotolken med hjälp av Maven:

$ mvn test

Du borde se följande text skrivas ut till konsolen:

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

Grattis! Du har fått till din första green bar med Arquillian!

En närmare titt

Hur vet du att CDI verkligen fungerade? För allt du vet är att Arquillian skapade en ny instans av klassen Greeter och injicerade den i testet utan någon hjälp av CDI. Låt oss visa hur det ligger till.

Skapa en ny CDI-böna med namnet PhraseBuilder i paketet org.arquillian.example som ska kunna skapa fraser utifrån mallar.

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}!");
    }
}

Härnäst, öppna klassen Greeter och skapa en ny konstruktor som injicerar PhraseBuilder med hjälp av konstruktorinjicering (så kallad constructor injection). Delegera sedan uppgiften att skapa en hälsning till den injicerade bönan.

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);
    }
}

För att ditt test ska fungera, måste en instans av PhraseBuilder skapas, dess @PostConstruct anropas samt att den måste injiceras i Greeter-klassens konstruktor när den skapas. Om allt detta fungerar kan vi vara säkra på att CDI fungerar.

Ett sista steg. Eftersom vi skapade en ny klass, måste vi vara säkra på att den läggs till i arkivet som returneras av metoden i testet som är annoterat @@Deployment@@. Det är bara att ändra följande rad:

.addClass(Greeter.class)

…till:

.addClasses(Greeter.class, PhraseBuilder.class)

Kör testet igen. Du bör nu se ytterligare en green bar! Känns bra, eller hur?

Debugga testet

Det här kommer att vara ett kort kapitel. Varför? Därför att ett Arquilliantest är så enkelt att du debuggar det precis på samma sätt som ett enhetstest. Lägg bara till en breakpoint på godtyckligt ställe—antingen i testet eller i koden för applikationen. Högerklicka sedan på filen och välj Debug As > JUnit Test. Nu debuggar du i containern! Labba runt och ha kul!

Om du använder en remote container, kommer inte Debug As att aktivera några breakpoints. Istället behöver du starta din container i debugläge och sedan koppla på din debugger. Detta för att testet körs i en annan JVM än den som testet kör i.

Som du nyss bevittnade, så är Arquillian det idealiska verktyget för att testa CDI-applikationer. Den tar hand om att ladda CDI-miljön och injicerar bönorna direkt in i testet. Det bästa av allt, om du använder en inbäddad CDI-container, körs testerna precis lika snabbt som ett enhetstest. Om det är allt du behöver, så kan du stänga ner guiden och börja skriva dina test på en gång.

Men! Berättar den inbäddade containern hela berättelsen? Kommer komponenterna att fungera ifall de körs i en riktig container?

En av sakerna som Arquillian piffar upp är att du kan köra samma test i olika kompatibla containers, oavsett om det är en annan inbäddad container eller en standalone container. Om du tänker köra flera containers, fortsätt läs nedan.

Lägga till fler containers

Som du lärde dig tidigare, Arquillian väljer container baserat på vilken containeradapter som finns på classpath. För att byta till en annan container byter du helt enkelt vilken containeradapter som finns på classpath innan du kör ditt test.

Det kan endast finnas en containeradapter på classpath vid någon given tidpunkt.

Ett sätt att byta ut biblioteken på classpath är att varje gång manuellt editera beroendena definierade i pom.xml. Men det skulle ju vara helt galet. Det finns ett mycket bättre sätt.

Vi kan använda Mavenprofiler för att partionera beroenden till grupper, en grupp för varje containeradapter och dess relaterade artefakter. När du kör testerna, aktivera en av grupperna för att välja vilken container som du vill använda, antingen genom en kommandoradsflagga (-P) eller via en inställning i din IDE.

Öppna upp pom.xml-filen och skapa en ny profil för Weld EE embedded genom att lägga in följande XML direkt under <dependencies>-elementet:

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.CR3</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.jboss.weld</groupId>
                <artifactId>weld-core</artifactId>
                <version>1.1.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 -->

Härnäst, ta bort beroendet till jboss-javaee-6.0 och Weld EE embedded containeradaptern från <dependencies>-elementet i huvudsektionen. Sektionerna <dependencies> samt <profiles> bör se ut så här när du väl är klar:

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.CR3</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.jboss.weld</groupId>
                <artifactId>weld-core</artifactId>
                <version>1.1.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 -->

Java EE API-beroendet har flyttats till profilen eftersom vissa containers, som Embedded GlassFish, redan tillhandahåller dessa bibliotek. Om vi skulle ha båda på classpath samtidigt skulle det resultera i konflikter. Därav denna classpathdans.

Nu ska vi inkludera två profiler till i pom.xml-filen inuti i <profiles>-elementet, först för 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.CR2</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 -->

och den andra för 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 -->

Nu har du möjligheten att köra testerna i en av tre containers.

Om du har problem med att sätta upp din pom.xml så här långt, så kan du ladda ner filen härifrån.

Testa i olika containers

När du uppdaterar projektet i Eclipse, så kommer du märka att det inte längre bygger. Det betyder att du behöver aktivera en av containerprofilerna. Låt oss aktivera profilen för Weld EE embedded för att gå tillbaka till vårt tidigare tillstånd.

Det finns två sätt att aktivera en Mavenprofil i Eclipse:

  1. Manuell konfiguration (det normala tillvägagångssättet)
  2. Maven profile selector (JBoss Tools)

Sätt aktiv Mavenprofil: Manuell konfiguration

För att sätta aktiv profil manuellt, följ följande steg:

  1. Högerklicka på projektet och välj Properties
  2. Välj Mavens properties-flik
  3. Fyll i profilens id i fältet Active Maven Profiles (t.ex. arquillian-weld-ee-embedded)
  4. Klicka på OK-knappen och godkänn ändringarna i projektet

Här är Maven properties-vyn som visar vilken profil vi har aktiverat:

Sätt aktiv Mavenprofil: Maven profile selector

Om du har JBoss Tools installerat är det mycket enklare att välja aktiv profil:

  1. Högerklicka på projektet och välj Maven > Select Active Profiles…
    (alternativt så kan du använda kortkommandot Ctrl+Shift+P eller knappen i verktygsfältet)
  2. Kryssa i rutan bredvid den profil du vill aktivera (e.g., arquillian-weld-ee-embedded)
  3. Klicka på OK-knappen.

Här är dialogfönstret som visar vilken Mavenprofil vi aktiverat:

När du väl har aktiverat profilen, ska du kunna köra testet igen med lyckat resultat.

Du vet redan att testet fungerar i Weld EE Embedded. Låt oss byta till GlassFish embedded genom att upprepa stegen ovan, den här gången genom att endast aktivera profilen arquillian-glassfish-embedded. Kör testet igen. Du bör nu se i konsolen att GlassFish startar… och ytterligare en green bar!

Du har nu kört samma test i två olika inbäddade containers, en CDI-container (Weld) och en Java EE container (GlassFish). Båda dessa exekveringar sker i samma process. För att vara säker på att komponenten fungerar i en ren miljö, behöver vi använda en standalone container. Låt oss byta till JBoss AS.

För att köra testet i en standalone-instans av JBoss AS behöver du först sätta upp den. Du kan antingen:

  1. ladda ner och packa upp den till en plats utanför projektet eller
  2. låta Maven ladda ner och packa upp den under ett bygge.

Följ dessa steg för att sätta upp JBoss AS 7 utanför projektet:

  1. Ladda ner JBoss AS 7
    (var säker på att versionen du väljer matchar versionen du specificerat i din pom.xml för <artifactId>jboss-as-arquillian-container-managed</artifactId>)
  2. Extrahera arkivet
  3. (valfritt) Sätt miljövariabeln JBOSS_HOME till sökvägen för den extraherade katalogen

För att istället låta Maven hantera detta, lägg till följande XML-fragment under <id>-elementet för din arquillian-jbossas-managed-profil:
div(filename). 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 -->

För att använda en managed JBoss AS 7-instans, behöver du också lite Arquillan-konfiguration. Skapa följande konfigurationsfil och specificera jbossHome att peka på sökvägen för där du har din JBoss AS 7 installerad. Om du använder Mavens dependency plugin, är sökvägen 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>

Byt nu den aktiva Mavenprofilen till arquillian-jbossas-managed och kör testet igen. Du bör nu se i konsolen att JBoss AS startar upp… och ytterligare en green bar!

Meddelandet som skrivs ut av System.out skrivs ut till din serverlogg istället för till konsolen.

Det är samma test, men den här gången kör den i en standardiserad (icke inbäddad) Java EE-container. Arquillian paketerar testet, deployar den till containern som ett Java EE-arkiv, exekverar testet remote, fångar resultatet och skickar tillbaka det till Eclipse’ JUnit-vy (eller till Maven surefire).

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

  • Sep 21, 2017: Fix(scripts) timeout for waiting for timestamp available on pages is by Matous Jobanek

See full history »