Testable development of CDI

Tutorial – Arquillian makes testing a breeze

DanAllenAndrewRubingerAslakKnutsen
Arquillian.1

It’s our opinion that Testing is Development; we’re not doing our job as programmers if we cannot ensure that our code is working as advertised. To that end, CDI has been a tremendous step forward for Java EE as a simplified POJO-based component model. Of course, CDI beans become such only within the context of a CDI Container, and that infers both starting a server and deploying into it. Until now, that work has been the responsibility of the developer; with the introduction of the Arquillian testing framework, these concerns can safely be put aside.

Arquillian is a platform that simplifies integration testing for
Java middleware. It deals with all the plumbing of container
management, deployment and framework initialization so you can
focus on the task at hand, writing your tests. Real tests.
Arquillian minimizes the burden on you – the developer – by
covering aspects surrounding test execution, including:

  • Managing the lifecycle of the container (start/stop),
  • Bundling the test class with dependent classes and resources
    into a deployable archive,
  • Enhancing the test class (e.g., resolving @Inject, @EJB and
    @Resource injections),
  • Deploying the archive to test (deploy/undeploy) and
  • Capturing results and failures.

To avoid introducing unnecessary complexity into the developer’s
build environment, Arquillian integrates seamlessly with familiar
testing frameworks (e.g., JUnit 4, TestNG 5), allowing tests to be
launched using existing IDE, Ant and Maven test plug-ins – without
any add-ons. This guide introduces you to Arquillian. After reading
this guide, you will be able to:

  • Add the Arquillian infrastructure to a Maven-based Java
    project
  • Write an Arquillian test case to assert the behaviour of a CDI
    bean
  • Execute the Arquillian test case in multiple compatible
    containers

You’ll learn all of these skills by incorporating Arquillian
into the test suite of a Java EE application with a Maven build.
We’ve designed this guide to be a fast read to get you started
quickly!

Assumptions

The easiest way to get started with Arquillian is to incorporate
it into the test suite of a project build that offers dependency
management. Today, the most widely-used build tool in this category
is Apache Maven. This guide will navigate you to your first green
bar using a sample Maven project.

Arquillian does not depend on Maven, or any specific build tool
for that matter. It works just as well – if not better – when used
in a project with an Ant or Gradle build. Ideally, the build tool
should offer dependency management as it simplifies the task of
including the Arquillian libraries since they are distributed in
the Maven Central repository

This guide assumes you have Maven available, either in your
command shell or your IDE. If you don’t, please install Maven now. You will
also need
JDK 1.6
 or better installed on your machine.

Create a new project

There are two ways we recommend you create a new Maven
project:

If you already have a Maven project, you can use this section as
review to ensure you have the proper dependencies before moving
on.

By far, JBoss Forge is the simpler approach, but this guide will
offer both options in the event you aren’t ready to adopt JBoss
Forge. Select from one of the two options above to jump to the
instructions.

Generate a project from a Maven archetype

First, create a Maven-based Java project using the command
below. Copy the text after the $ and paste it into your command
shell.

 

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

Respond to the prompts by entering the value shown after each
double colon below. Hit the Enter key after each line (as indicated
by <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>

This command generated a Maven-based Java project inside a new
folder named arquillian-tutorial under the current
directory. The file structure of the project is shown below:

  • src/
    • main/
      • java/ – Place all application Java source files here
        (under Java package)
      • resources/ – Place all application configuration files
        here
    • test/
      • java/ – Place all test Java source files heres (under
        Java package)
      • resources/ – Place all test configuration files here
        (e.g., arquillian.xml)
  • pom.xml – The Maven build file. Tells Maven how your
    project should be built.

The project is preconfigured to use Java 6 and JUnit 4.8, the
minimum required versions of Java and JUnit for using Arquillian,
respectively.

The generator also created a Java package named
org.arquillian.example underneath the two java
folders. You should put your Java source files in this package
rather than at the root of the java folder.

Arquillian also supports TestNG 5. However, we will be using
JUnit throughout this guide.

Go ahead and open up the pom.xml in your editor. You
should see an XML file containing basic project information, a
build section and a dependencies section. You can remove all the
elements below the JUnit dependency as they aren’t required.

After making the change, you should end up with the contents
seen in listing 1 (trimmed for brevity).

Listing 1

pom.xml
<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>
   <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>

We’re going to be writing Java EE 6 components. Therefore, we
also need to add the Java EE 6 API to the classpath so we can
compile these components.

Open up the pom.xml file once again and add the following XML
fragment directly inside the <dependencies> element.
Listing 2 shows how the section should look once you’re done.

Listing 2

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

We strongly recommend that you do not use the Java EE API
artifact with coordinatesjavax:javaee-api. That bundle
contains classes with stripped method bodies, which will cause your
application to throw strange Absent Code errors if left on the
classpath at runtime (even when running tests). Read the
FAQ
under if you want more background.

The foundation of your project is now ready! Skip to the next
section to open the project in
Eclipse
 so we can start writing some code!

Create a Project Using Forge

JBoss
Forge
 is a command shell for rapid-application development
in a standards-based environment. Another way to think of it is
that it’s like Maven Archetypes on steroids.

Installing Forge is a relatively short process, and this guide
will take you through the fundamentals. Follow these simple steps
to get it installed:

  1. Download Forge and unzip it into a folder on your harddrive,
    which we’ll call $FORGE_HOME
  2. We’ll assume you extracted the distribution to a folder named
    forge in your home directory
  3. Add $FORGE_HOME/bin to your path (Windows, Linux or Mac
    OSX)

On Unix-based operating systems, adding Forge to your path
typically means editing your $HOME/.bashrc or
$HOME/.profile; you will need to set the following
environment variables:

$ export FORGE_HOME=$HOME/forge/

$ export PATH=$PATH:$FORGE_HOME/bin

On Windows, you will need to right-click on Control Panel, then
click System Properties, open the Advanced tab, then click
Environment Variables and add these two entries visually. We
recommended setting User variables for Forge, unless you have
placed the unzipped distribution in a folder where all users can
access it.

Now that Forge is installed (i.e., extracted), open a command
prompt (a shell) and run the forge command (figure 1):

$ forge 
[no project] ~ $

That’s it! You’ve got Forge up and running. Now it’s time to
create the project.

Inside the Forge shell, execute the following command to create
a blank project, much like we created a project using the Maven
Archetype above:

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

This command generates a Maven-based Java project inside a new
folder named arquillian-tutorial under the current directory. The
file structure of the project Forge generates is shown below:

  • src/
    • main/
      • java/ – Place all application Java source files here
        (under Java package)
      • resources/ – Place all application configuration files
        here

        • META-INF/
          • forge.xml – An empty Forge settings file
    • test/
      • java/ – Place all test Java source files heres (under
        Java package)
      • resources/ – Place all test configuration files here
        (e.g., arquillian.xml)
  • pom.xml – The Maven build file. Tells Maven how your
    project should be built.

Forge also makes the project folder your current directory
within the Forge shell.

[arquillian-tutorial] arquillian-tutorial $

By default, Forge sets up the project to use Java 1.6, the
minimum required version of Java to use Arquillian, a nice
convenience. What we need to add now is the Java EE APIs. That’s
done using the project add-dependency command below:

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

You will also need to add JUnit 4.8, the minimum required
version of JUnit to use Arquillian, as a test-scoped
dependency:

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

The result of the pom.xml that Forge
generates is shown in Listing 3.

Listing 3

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 is now distributed in the Maven Central repository,
so the JBoss Public repository declaration in the pom.xml
is unnecessary and can be removed. Keep in mind, though, you may
need it to retrieve other JBoss software not available in Maven
Central. If you follow the camp that consider repositories
explicitly defined in your project’s pom.xml to be an
antipattern, then read the instructions
under  to enable the repository globally in your
settings.xml file.

The foundation of your project is now ready! Let’s now open the
project in Eclipse so we can start writing some code!

Open the Project in Eclipse

When developing a Java project, you’ll likely use an IDE, such
as Eclipse. That’s why Arquillian has been designed to be IDE
friendly, meaning you can run Arquillian tests from the IDE without
making unconventional changes. So let’s start taking advantage of
the IDE immediately.

Begin by launching Eclipse. Now, since this is a Maven project,
you need the Maven Integration for Eclipse(m2e) plug-in installed to open the
project. If you don’t already have the integration installed, the
simplest way to get it is to install JBoss Tools. Follow these steps to
install it from the Eclipse Marketplace (sort of like the app store
for Eclipse).

  1. Select Help | Eclipse Marketplace… from the main menu
  2. Type “jboss tools” in the Find input field (no quotes) and
    press Enter
  3. Click the Install button next to JBoss Tools (Indigo)
  4. Complete the install wizard, then restart Eclipse if
    prompted

JBoss Tools provides a nice environment for developing Java EE
applications, including excellent CDI support. Don’t worry, it’s
not a heavyweight plugin.

However, if you just want the Maven integration without the
extras that JBoss Tools brings, you can follow these steps
instead:

  1. Select Help | Eclipse Marketplace… from the main menu
  2. Type “maven” in the Find input field (no quotes) and press
    Enter
  3. Click the Install button next to Maven Integration for
    Eclipse
  4. Complete the install wizard, then restart Eclipse if
    prompted
  5. Repeat the steps to install the Maven Integration for Eclipse
    WTP

Once you have the Maven Integration plugin installed, follow
these steps to open the project:

  1. Select File | Import… from the main menu
  2. Type “existing maven” in the input source field
  3. Select the option Existing Maven Projects, then click the Next
    button
  4. Click the Browse… button
  5. Navigate the project folder on your filesystem, then click the
    OK button
  6. Click the Finish button to open the project

Eclipse will recognize the Maven project and open it in the
Project Navigator view. If you expand the project, it should look
similar to figure 2. Now we can really get down to business!

Create a Component

In order to write an Arquillian test, we need to have a
component for it to test. Let’s begin by creating a basic component
so that you can learn how to execute an Arquillian test without
other distractions. We’ll gradually move to more complex
scenarios.

In your IDE, create a new Java class named Greeter in the
org.arquillian.example package. Replace the contents of the file
with this greeter logic (Listing 4).

Listing 4

 

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

 

We want to verify that this class behaves properly when invoked
as a CDI bean. Of course, we could simply write a unit test. But
let’s pretend that the bean uses enterprise services such as
dependency injection and messaging and must be used inside a
container. (Besides, that way we give it room to grow).

To use the class as a CDI bean, we’ll be injecting it into the
test using the @Inject annotation. That calls
for an Arquillian test, which means it’s time to add the Arquillian
API to the project!

Add the Arquillian APIs

Once again open up the pom.xml file, located
in the root folder of the project, in your editor. We need to
instruct Maven which versions of the artifacts to use. Insert the
following XML fragment directly above
the <build> element to import the BOM, or
version matrix, for Arquillian’s transitive dependencies.

 

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

 

Next, append the following XML fragment directly under the last
<dependency> element to add the Arquillian JUnit
integration:

 

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

 

The Arquillian JUnit integration artifact also adds the
Arquillian and ShrinkWrap APIs to the test
classpath. You need all of these libraries to write and compile a
JUnit Arquillian test. To use TestNG instead of JUnit,
substitute the Arquillian JUnit integration with the Arquillian
TestNG integration. If you’re having trouble with
the pom.xml up to this point, you can download
the file from the
gist
. You’re all set to write your first Arquillian test!

Write an Arquillian Test

An Arquillian test looks just like a unit test, just with some
extra flair. Let’s return to the IDE. If you get the message
“Project configuration is out of date with pom.xml”,
then right click and
selectProject | Maven | Update Project
Configuration to resync the project.

Begin by creating a new JUnit test case
in src/test/java under
the org.arquillian.example package and name
it GreeterTest. You won’t need the typical setup and teardown
methods since Arquillian is doing most of the heavy lifting. Here’s
what we have so far:

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

Now, about that flair. An Arquillian test case must have three
things:

  1. A @RunWith(Arquillian.class) annotation on the
    class
  2. A static method annotated with @Deployment that
    returns a ShrinkWrap archive
  3. At least one method annotated with @Test

The @RunWith annotation tells JUnit to use Arquillian
as the test controller. Arquillian then looks for a static method
annotated with the @Deployment annotation to retrieve the
test archive (i.e., micro-deployment). Then some magic happens and
each @Test method is run inside the container
environment.

What’s a test archive?

The purpose of the test archive is to isolate the classes and
resources which are needed by the test from the remainder of the
classpath. Unlike a normal unit test, Arquillian does not simply
dip into the entire classpath. Instead, you include only what the
test needs (which may be the entire classpath, if that’s what you
decide). The archive is defined using ShrinkWrap, which is a Java
API for creating archives (e.g., jar, war, ear) in Java. The
micro-deployment strategy let’s you focus on precisely the classes
you want to test and, as a result, the test remains very lean.

ShrinkWrap also supports resolving artifacts (libraries) and
create configuration files programmatically, which can then be
added to the test archive. For a more thorough introduction to
ShrinkWrap, see the ShrinkWrap introduction
guide
. Let’s add that Arquillian flair to the test (listing
5).

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

Using ShrinkWrap, we’ve defined a Java archive (jar) as
the deployment that includes the Greeter class that the test will
invoke and an empty beans.xml in the META-INF
directory to activate CDI in this archive.

Now all we need to do is inject the Greeter instance into a
field directly above the test method and replace the unimplemented
test method with one that asserts the behavior of the bean. To give
you that warm fuzzy feeling, we’ll also print the greeting to the
console.

src/test/java/org/arquillian/example/GreeterTest.java
// clip
@Inject
Greeter greeter;

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

Listing 6 shows how the test should look when you’re done.

Listing 6

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

You’ve written your first Arquillian test! Ah, but you’re
probably wondering how to run it. If you’re thinking, “Just like a
unit test” you’re correct! However, we first need to add a
container adapter to the classpath.

Add a Container Adapter

We’ve been talking a lot about testing in a container, but so
far we have not mentioned which one. That’s because it’s a runtime
decision. Arquillian selects the target container based on which
container adapter is available on the test classpath. That means
we’ll be adding more libraries to the project.

An Arquillian test can be executed in any container that is
compatible with the programming model used in the test (as long as
the container has an Arquillian adapter). Our test is using the CDI
programming model, so we need to use any container to supports CDI.
We want fast turnaround during development, so we’ll start with the
Weld EE embedded container.

Open the pom.xml file again and add the
following group of dependencies directly below the
other<dependency> elements (listing 7).

Lisiting 7

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.1.Final</version>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-simple</artifactId>
   <version>1.5.10</version>
   <scope>test</scope>
</dependency>
<!-- clip -->

To summarize, here are the three libraries you need to use
Arquillian (with JUnit):

  1. Arquillian JUnit integration
  2. Arquillian container adapter for the target container
  3. Container runtime (embedded container) or container client
    (remote container)

We’re using an embedded container in this example, so we need
the container runtime, Weld.

Now back to the test.

    

Run the Arquillian Test

Once you add all the necessary Arquillian libraries to the
classpath, you can run an Arquillian test just like a unit test,
whether you are running it from the IDE, the build script or any
other test plugin. Let’s run the test in Eclipse.

From the IDE window, right click on the GreeterTest.java file in
the Package Explorer (or in the editor) and select Run As | JUnit
Test from the context menu (see fig. 3)

Fig.3: Starting the test

When you run the test, you should see the following lines
printed to the console:

26 [main] INFO org.jboss.weld.Version – WELD-000900 1.1.1
(Final)

Hello, Earthling! You should then see the JUnit view appear,
revealing a green bar (fig. 4)!

Fig.4: JUnit view revealing a green bar

You can also run the test on the commandline using Maven:

$ mvn test

You should see the following lines printed to the console:

——————————————————-

T E S T S

——————————————————-

Running org.arquillian.example.GreeterTest

21 [main] INFO org.jboss.weld.Version – WELD-000900 1.1.1
(Final)

Hello, Earthling!

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed:
0.858 sec

Congratulations! You’ve earned your first green bar with
Arquillian!

A Closer Look

How do you know that CDI really worked? For all you know,
Arquillian created a new instance of theGreeter class and injected
it into the test without any involvement from CDI. Let’s prove it’s
there. Create a new CDI bean
named PhraseBuilder in
the org.arquillian.example package that can
create phrases from templates.

Listing 8

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

Next, open up the Greeter class and create a new constructor
that will inject PhraseBuilder using constructor
injection. Then, delegate the task of creating the greeting to the
injected bean (listing 9)

Listing 9

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

Now, in order for the test to work, an instance of PhraseBuilder
must be created, its @PostConstructmethod invoked and must be
injected into the constructor of Greeter when an instance of
Greeter is created. We can be certain CDI is at work if all that
comes together.

One last step. Because we created a new class, we must be sure
that it’s getting added to the archive returned by the @Deployment
method in the test. Simply change the line:

.addClass(Greeter.class)
...to read:
.addClasses(Greeter.class, PhraseBuilder.class)

Run the test again. You should get another green bar! Feels
good, doesn’t it?

Debug the Test

This is going to be a short chapter. Why? Because an Arquillian
test is so straightforward that you debug it exactly how you debug
a unit test. Just add a breakpoint anywhere – either in the test or
in the application code. Then right-click on the file and
select Debug As | JUnit Test (figure 5).You’re
now debugging in the container! Have fun poking around!

Fig.5: Debugging the container

If you are using a remote container, Debug As does not cause breakpoints to be
activated. Instead, you need to start the container in debug mode
and attach the debugger. That’s because the test is run in a
different JVM than the original test runner.

As you’ve just witnessed, Arquillian is the ideal tool for
testing CDI applications. It takes care of loading the CDI
environment and injecting beans directly into the test. Best of
all, when using an embedded CDI container, the test runs just as
quickly as a unit test. If that’s all you need, then you can exit
the tutorial now and start writing tests.

But! Is the embedded container telling the whole story? Will the
component work if running inside a full container?

One of the perks of Arquillian is that you can run the same test
in different compatible containers, whether it’s another embedded
container or a standalone container. If you intend to use multiple
containers, read on.

Add More Containers

As you learned earlier, Arquillian selects the container based
on which container adapter is on the classpath. To switch to
another container, you just change which container adapter is on
the classpath before you run the test. There can only be one
container adapter on the classpath at a given time.

One way to swap the libraries on the classpath is to manually
edit the dependencies defined in thepom.xml each time. But
that’s just crazy. There’s a much better way.

We can use Maven profiles to partition the dependencies into
groups, one group for each container adapter and its related
artifacts. When running the tests, you activate one of those groups
to select the container using either a commandline flag (-P) or a
preference in the IDE.

Open up the pom.xml and
create a new profile for Weld EE embedded by inserting the
following XML directly under the <dependencies> element (listing
10).

Listing 10

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.1.Final</version>
               <scope>test</scope>
           </dependency>
           <dependency>
               <groupId>org.slf4j</groupId>
               <artifactId>slf4j-simple</artifactId>
               <version>1.5.10</version>
               <scope>test</scope>
           </dependency>
       </dependencies>
   </profile>
</profiles>
<!-- clip -->

Next, remove the jboss-javaee-6.0 dependency
and the dependencies for the Weld EE embedded container adapter
from the main <dependencies> section. Listing
11 shows how the <dependencies> and <profiles> sections should look
when you’re done.

Listing 11

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.1.Final</version>
               <scope>test</scope>
           </dependency>
           <dependency>
               <groupId>org.slf4j</groupId>
               <artifactId>slf4j-simple</artifactId>
               <version>1.5.10</version>
               <scope>test</scope>
           </dependency>
       </dependencies>
   </profile>
</profiles>
<!-- clip -->

The Java EE API dependency has been moved to the profile since
some containers, like Embedded GlassFish, already provide these
libraries. Having both on the classpath at the same time would
result in conflicts. So we have to play this classpath dance.

We’ll now include two additional profiles in
the pom.xml inside
the <profiles> element, the first for
Embedded GlassFish (listing
12).

Listing 12

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.extras</groupId>
           <artifactId>glassfish-embedded-all</artifactId>
           <version>3.1</version>
           <scope>provided</scope>
       </dependency>
   </dependencies>
</profile>
<!-- clip -->

and the other for 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.0.Final</version>
           <scope>test</scope>
       </dependency>
   </dependencies>
</profile>
<!-- clip -->

Now you have the choice of running the tests in one of three
containers. If you’re having trouble with the pom.xml up to this
point, you can download the file from the gist.

Test Across Containers

When you refresh the project in Eclipse, you’ll notice that it
no longer builds. That’s because you need to activate one of the
container profiles. Let’s activate the Weld EE embedded profile to
restore the previous state. There are two ways to activate a Maven
profile in Eclipse:

  1. Manual configuration (standard approach)
  2. Maven profile selector (JBoss Tools)

Set active Maven profile: Manual
configuration

To set the active profile manually, follow these steps:

  1. Right click on the project and select Properties
  2.  Select the Maven properties tab
  3. Enter the profile id in the Active Maven Profiles field (e.g.,
    arquillian-weld-ee-embedded)
  4. Click the OK button and accept the project changes

Figure 6 displays the Maven properties screen showing the
profile we’ve activated:

Set active Maven profile: Maven profile
selector

If you have JBoss Tools installed, selecting the active profile
becomes much easier:

  1. Right click on the project and select Maven > Select Active
    Profiles…
  2. (alternatively, you can use the keybinding Ctrl+Shift+P or the
    button in the toolbar)
  3. Check the box next to the profile you want to activate (e.g.,
    arquillian-weld-ee-embedded)
  4. Click the OK button

Figure 7 displays the Maven profile selector dialog showing the
profile we’ve activated:

Once you have activated the profile, you should be able to run
the test again successfully.

You already know the test works in Weld EE Embedded. Let’s
switch to GlassFish Embedded by repeating the steps above, this
time activating only the arquillian-glassfish-embedded profile. Run
the test again. You should see GlassFish start in the console…and
another green bar!

You’ve now run the same test on two different embedded
containers, a CDI container (Weld) and a Java EE container
(GlassFish). Both of these executions are in process. To really be
sure the component works in a pure environment, we need to use a
standalone container. Let’s switch to using JBoss AS.

To run the test on a standalone instance of JBoss AS, you first
need to set it up. You can either:

  1. download and unpack it in a location outside the project
    or
  2. you can have Maven download and unpack it during a build.

Follow these steps to setup JBoss AS 7 outside the project:

  1. Download JBoss
    AS 7 
  2. (be sure the version you select matches the version you’ve
    defined in your pom.xml for
    <artifactId>jboss-as-arquillian-container-managed</artifactId>)
  3. Extract the archive
  4. (optional) Set the JBOSS_HOME environment variable to
    the path of the extracted directory

To have Maven handle this task for you instead, add the
following XML fragment under the <id> element of the
arq-jbossas-managed profile (listing 13).

Listing 13

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.0.Final</version>
                               <type>zip</type>
                               <overWrite>false</overWrite>
                               <outputDirectory>target</outputDirectory>
                           </artifactItem>
                       </artifactItems>
                   </configuration>
               </execution>
           </executions>
       </plugin>
   </plugins>
</build>
<!-- clip -->

To target a managed JBoss AS 7 instance, you also need a small
bit of Arquillian configuration. Create the following configuration
file and assign the value of
the jbossHome property to the location where
JBoss AS 7 is installed. If you’re using the Maven dependency
plug-in, the location
istarget/jboss-as-7.0.2.Final (listing 14).

Listing 14

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-7-managed" default="true">
       <configuration>
           <property name="jbossHome">target/jboss-as-7.1.0.Final</property>
       </configuration>
   </container>
</arquillian>

Now change the active Maven profile
to arquillian-jbossas-managed, then run the test
again. You should see JBoss AS starting in the console…and yet
another green bar!

The message printed to System.out gets
written to the server log instead of the console.

That’s the same test, this time running in a standard
(non-embedded) Java EE container. Arquillian packages the test,
deploys to the container as a Java EE archive, executes the tests
remotely, captures the results and feeds them back to the Eclipse
JUnit result view (or in the Maven surefire results). You can read
more about how this lifecycle works in the Arquillian reference

guide
.

Author

DanAllenAndrewRubingerAslakKnutsen

All Posts by DanAllenAndrewRubingerAslakKnutsen

Comments
comments powered by Disqus