Enterprise Java

Testing Java EE 6 with Arquillian (incl. JPA, EJB, Bean Validation and CDI)

For a very long time, I heard quite a lot of people saying good things about Arquillian. Whilst I have been reading articles around its use, I couldn’t really find one that covers some of the aspects that I find important, all in a single article. Granted, I haven’t looked hard enough.

Points that I would like to cover are:
 
 
 
 
 

  • The use of JPA. I simply use EclipseLink here,
  • The use of in-memory database,
  • The use of CDI injection,
  • The use of EJB, say local Stateless session bean,
  • The use of JSR-303 Bean Validation,
  • The use of (embedded) glassfish for integration testing.

It took me a while to gather information to get such project up and running. I thought I dedicate this post to help out those who’s got similar requirement. So, what are we waiting for!? Let’s start!!!

Configure pom.xml

Of course, we need to configure out project to use Arquillian, and also use EclipseLink as the persistence provider. But, bear in mind that we also decide before that we want to use an in-memory database. You might want to include your dependency here, in this pom.xml. I, however, decide to use Derby, which is available in the standard Oracle Java SDK classpath.

Anyway, so the pom.xml would look like this:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
<?xml version="1.0" encoding="UTF-8"?>
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
 
 
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>inout</artifactId>
        <groupId>id.co.dwuysan</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
 
    <groupId>id.co.dwuysan</groupId>
    <artifactId>inout-ejb</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>ejb</packaging>
 
    <name>inout-ejb</name>
 
    <properties>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <netbeans.hint.deploy.server>gfv3ee6</netbeans.hint.deploy.server>
    </properties>
 
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.jboss.arquillian</groupId>
                <artifactId>arquillian-bom</artifactId>
                <version>1.0.0.Final</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
 
    <dependencies>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
            <version>2.3.2</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>javax.persistence</artifactId>
            <version>2.0.3</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
            <version>2.3.2</version>
            <scope>provided</scope>
        </dependency>
 
        <!-- test -->
 
        <dependency>
            <groupId>org.jboss.arquillian</groupId>
            <artifactId>arquillian-bom</artifactId>
            <version>1.0.3.Final</version>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>org.glassfish.main.extras</groupId>
            <artifactId>glassfish-embedded-all</artifactId>
            <version>3.1.2.2</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.arquillian.container</groupId>
            <artifactId>arquillian-glassfish-embedded-3.1</artifactId>
            <version>1.0.0.CR3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.arquillian.junit</groupId>
            <artifactId>arquillian-junit-container</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
 
        <!-- environment requirement -->
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.12.4</version>
                <configuration>
                    <argLine>-XX:-UseSplitVerifier</argLine>
                    <systempropertyvariables>
                        <java.util.logging.config.file>
                            ${basedir}/src/test/resources/logging.properties
                        </java.util.logging.config.file>
                    </systempropertyvariables>
                    <systemProperties>
                        <property>
                            <name>derby.stream.error.file</name>
                            <value>target/derby.log</value>
                        </property>
                    </systemProperties>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <compilerArguments>
                        <endorseddirs>${endorsed.dir}</endorseddirs>
                    </compilerArguments>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-ejb-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <ejbVersion>3.1</ejbVersion>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.1</version>
                <executions>
                    <execution>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${endorsed.dir}</outputDirectory>
 
                            <silent>true</silent>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>javax</groupId>
                                    <artifactId>javaee-endorsed-api</artifactId>
                                    <version>6.0</version>
                                    <type>jar</type>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>java.net</id>
            <url>http://download.java.net/maven/</url>
        </repository>
        <repository>
            <id>JBOSS_NEXUS</id>
        </repository>
        <repository>
            <id>eclipselink</id>
            <layout>default</layout>
            <name>Repository for library EclipseLink (JPA 2.0)</name>
        </repository>
    </repositories>
</project>

As shown in the XML above, the things we have done are:

  • Include the use of Arquillian, using embedded Glassfish
  • Include the use of EclipseLink
  • Set Derby props for later use, i.e. logging and location of the database created.

Create out ‘case’, i.e. our JPA, EJB, CDI

Of course, we first start by creating a case, so that we can then later test it. I assume you are familiar with JPA, EJB, CDI. Hence, following are very quick glimpses of classes using these technology.

JPA class, Outlet.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package id.co.dwuysan.inout.entity;
 
// imports omitted
 
@Entity
@NamedQueries({
    @NamedQuery(
        name = Outlet.FIND_BY_NAME,
        query = "SELECT o FROM Outlet o WHERE o.name = :name")
})
public class Outlet implements Serializable {
 
    public static final String FIND_BY_NAME = "Outlet#FIND_BY_NAME";
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
 
    @Column(name = "code", length = 50, insertable = true,
            updatable = false, unique = true)
    @Size(message = "{dwuysan.nameSizeError}", min = 1, max = 50)
    @NotNull
    private String name;
 
    /* Accessors and mutators goes here */
 
    @Override
    public int hashCode() {
        // omitted
    }
 
    @Override
    public boolean equals(Object obj) {
        // omitted
    }
}

Persistence.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
  <persistence-unit name="inoutPU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>inoutDb</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
    </properties>
  </persistence-unit>
</persistence>

Then let’s add a producer method to supply our PersistenceContext, as well as our EJB that uses it.

EntityManagerProducer.java

01
02
03
04
05
06
07
08
09
10
11
12
package id.co.dwuysan.inout.util;
 
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
 
public class EntityManagerProducer {
 
    @Produces
    @PersistenceContext
    private EntityManager em;
}

OutletService.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package id.co.dwuysan.inout.service;
 
// imports omitted
 
@Stateless
@LocalBean
public class OutletService {
 
    @Inject
    private EntityManager em;
 
    @Resource
    private Validator validator;
 
    public Outlet createOutlet(final String name) {
        final Outlet outlet = new Outlet();
        outlet.setName(name);
        final Set<ConstraintViolation<Outlet>> violations = this.validator.validate(outlet);
        if (!violations.isEmpty()) { throw new ConstraintViolationException(new HashSet<ConstraintViolation<?>>(violations)); }
        return this.em.merge(outlet);
    }
 
    public Outlet getOutlet(final String name) {
        final Query query = this.em.createNamedQuery(Outlet.FIND_BY_NAME);
        query.setParameter("name", name);
        try {
            return (Outlet) query.getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }
}

Sets beans.xml and ValidationMessages.properties

Don’t forget to:

      • add beans.xml under src/main/resources/META-INF, and
      • add ValidationMessages.properties under src/main/resources, and
      • configure your message dwuysan.nameSizeError=error message you like here

Configure for testing purpose

At this point, should you deploy, it should work. HOWEVER, that’s not our goal. We would like to get it working under Arquillian, using embedded Glassfish.

Firstly, let’s prepare configuration for embedded glassfish, using Derby database. The file is glassfish-resources.xml. In my case, I simply put this file under a new directory, mainly for separation, i.e. src/test/resources-glassfish-embedded/glassfish-resources.xml.

glassfish-resources.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC
    "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN"
<resources>
    <jdbc-resource pool-name="ArquillianEmbeddedDerbyPool"
                   jndi-name="jdbc/arquillian"/>
    <jdbc-connection-pool name="ArquillianEmbeddedDerbyPool"
                          res-type="javax.sql.DataSource"
                          datasource-classname="org.apache.derby.jdbc.EmbeddedDataSource"
                          is-isolation-level-guaranteed="false">
        <property name="databaseName" value="target/databases/derby"/>
        <property name="createDatabase" value="create"/>
    </jdbc-connection-pool>
</resources>

It is quite self-explanatory. Just remember to configure the database to be created on target/databases/derby so that when you do mvn clean it will be cleaned.

Next step, is to configure Arquillian to “recognise” this glassfish-resources.xml. To do this, add arquillian.xml under the src/test/resources directory.

glassfish-resources.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    <engine>
        <property name="deploymentExportPath">target/arquillian</property>
    </engine>
    <container default="true" qualifier="glassfish">
        <configuration>
            <property name="resourcesXml">src/test/resources-glassfish-embedded/glassfish-resources.xml</property>
        </configuration>
    </container>
</arquillian>

The next step is to prepare our persistence.xml. We already have one, but remember we need to supply the one which is in-memory, and make use of the jdbc connection provided by our embedded Glassfish (see glassfish-resources.xml above, which provide the jdbc-resource-pool under the JNDI name jdbc/arquillian. In my case, I named this test-persistence.xml, under src/test/resources

test-persistence.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    <persistence-unit name="inoutPU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/arquillian</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <shared-cache-mode>ALL</shared-cache-mode>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:derby:target/databases/derby;create=true" />
            <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
            <property name="eclipselink.target-database" value="Derby"/>
            <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
            <property name="eclipselink.debug" value="OFF"/>
            <property name="eclipselink.weaving" value="static"/>
            <!--<property name="eclipselink.logging.level" value="FINEST"/>-->
            <property name="eclipselink.logging.level.sql" value="FINE"/>
            <property name="eclipselink.logging.parameters" value="true"/>
            <!--<property name="eclipselink.logging.level.cache" value="FINEST"/>-->
            <property name="eclipselink.logging.logger" value="DefaultLogger"/>
        </properties>
    </persistence-unit>
</persistence>

When everything is ready, we are now ready to write our unit test, with Arquillian. In this case, it is best to test our service EJB, since that’s where we are going to use JPA, CDI, and the Validation.

OutletServiceTest.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package id.co.dwuysan.inout.service;
 
// imports omitted
 
@RunWith(Arquillian.class)
public class OutletServiceTest {   
 
    @Inject
    private OutletService outletService;
 
    @Deployment
    public static JavaArchive createTestArchive() {
        return ShrinkWrap.create(JavaArchive.class)
                .addClass(Outlet.class)
                .addClass(OutletService.class)
                .addClass(EntityManagerProducer.class)
                .addAsManifestResource("test-persistence.xml",
                    ArchivePaths.create("persistence.xml"))
                .addAsManifestResource("META-INF/beans.xml",
                    ArchivePaths.create("beans.xml"))
                .addAsResource("ValidationMessages.properties");
    }
 
    @Test
    public void testCreateOutlet() throws Exception {
        final String outletName = "Outlet 001";
        final Outlet outlet = this.outletService.createOutlet(outletName);
        Assert.assertNotNull(outlet);
 
        // check retrieval
        final Outlet retrievedOutlet = this.outletService.getOutlet(outletName);
        Assert.assertEquals(outlet.getName(), retrievedOutlet.getName());
    }
 
    @Test(expected = ConstraintViolationException.class)
    public void testCreateOutletWithEmptyName() throws Exception {
        try {
            final Outlet outlet = this.outletService.createOutlet("");
        } catch (EJBException e) {            
            final ConstraintViolationException cve = (ConstraintViolationException) e.getCause();
 
            Assert.assertEquals("Total error message should only be one",
                1, cve.getConstraintViolations().size());           
            Assert.assertEquals("Message must be correct",
                "Name must be provided",
                cve.getConstraintViolations().iterator().next().getMessage());
            throw cve;
        }
    }
}

In the above example, the first test is testing the successful case. Given a name, a retrieval should result in an Outlet entity return providing the same name as parameter. Underneath the surface though, if we look back at the body of the OutletService.java, we are actually testing:

      • Persistence (JPA), into the underlying Derby
      • EJB injected into this test/li>
      • PersistenceContext injected via Producer method (CDI)
      • Testing no validation violated
      • Testing our NamedQuery

The second test is aimed to test that the message is interpolated correctly. Referring to what mentioned previously, for my error message, I have put the following entry in my ValidationMessages.properties:

1
dwuysan.nameSizeError=Name must be provided

So, we need to test that the message from Bean Validation in Outlet is interpolated correctly.

Please pay attention to the second test. Notice that firstly, we are catching EJBException. That is because any runtime exception thrown inside an EJB will be wrapped into EJBException, hence the need to extract it via #getCause().

So, there you go. You can now add more services and start your Arquillian test. Happy coding

Future investigation

Many Java EE application of course requires authentication and authorisation, which is generally done via JAAS. For example, using my simple example above, supposed that the service is to be modified to retrieve the outlets the current user has access to, then of course we need to get the current user’s identity. Generally, this is done via EJBContext.getCallerPrincipal(). I wonder how we can do this using Arquillian and embedded Glassfish.
 

Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy
Subscribe
Notify of
guest


This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Aslak Knutsen
11 years ago

Heya!

Nice article. Great job of explaining the moving parts.

Just one little note; there is no need to include the arquillian-bom in the pom.xml’s dependency section, it’s only required in the dependencyManagement section :)

-aslak-

Siarhei
Siarhei
11 years ago

It would be nice to post sources somewhere.

Back to top button