Document Version 1.0
Copyright © 2012 beijing.beijing.012@gmail.com
Keywords:
JEE integration test, JEE unit test, arquillian sample, JBoss 5, JBoss 7, EJB test, arquillian dependencies, arquillian enbedded container, managed container, remote container, arquillian JUnit
Table of Contents
1. Create a simple Maven project in Eclipse
2. Create project's pom.xml file
3. Implement source code and test code
4. Download JBoss "jboss-5.1.0.GA"
5. arquillian.xml
6. Run the tests
6.1 Set system properties "PATH" and "JAVA_HOME"
6.2 Run tests6.2 Run tests
7. Finding the EJB with annotation
8. Run test again
9. Troubleshooting
2. Create project's pom.xml file
3. Implement source code and test code
4. Download JBoss "jboss-5.1.0.GA"
5. arquillian.xml
6. Run the tests
6.1 Set system properties "PATH" and "JAVA_HOME"
6.2 Run tests6.2 Run tests
7. Finding the EJB with annotation
8. Run test again
9. Troubleshooting
In the part 1-2 of the "Tutorial EJB3 Integration Test with Arquillian" we successfully tested EJB with Arquillian, deployed on JBoss 7 managed and remote container.
But there are still cases, where upgrade to JBoss 7 is not an option, for whateve resons, therefore Arquillian test need to be done in older version of JBoss containers. Compare to the Arquillian test with JBoss 7, Arquillian test with older JBoss versionis are not so good documented.
In the part 3-5 of this serial I would try to to provide an "one stop" guide to setting up Arquillian with JBoss 5 container.
Arquillian part3 - JBoss 5 managed container
1. Create a simple Maven project in Eclipse
Follow the section 1 of "EJB3 Integration Test with Arquillian part1-JBoss 7 managed container" to create a new Eclipse project "testarq_jb5_managed". Be sure in step2, to name the ArtifactId as "testarq_jb5_managed".
2. Create project's pom.xml file
As you may remember, for Arquillian with JBoss 7, there is a dependency in pom.xml file called "arquillian-bom". We used this bom dependency to resolve all the Aquillian and JBoss artifacts. But unfortunately for JBoss 5, I could not find such a bom dependency, so all the dependencies in this pom.xml need to be configured "manually".
Create a "pom.xml" file in the "testarq_jb5_managed" project, which we created in section 1. Replace the content of "pom.xml" will the content below:
! Instead of using the default "maven central repository", we have to switch repository to "maven-us.nuxeo.org", as configured in the repositories section of the above "pom.xml" file.
Maven could not find some dependencies in "central maven repository" ( maybe they were removed, or not hosted there at all °_°).
3. Implement source code and test code
As code sample we will take a typical use case in JEE application:
A business layer/class uses a DAO (data access object) to access business data. Here business class and DAO class are both stateless session bean.
To implement and test the above use case, we need to create following classes in the "testarq_jb5_managed" project:
2 for bussiness classes:
GrussGottEjbLocal.java
GrussGottEjb.java
2 for DAO classes:
HalloDaoLocal.java
HalloDao.java
and the test class:
TestGrussGott.java
Now the "testarq_jb5_managed" project in Eclipse will looks like:
Replace the content of java files with following contents:
HalloDaoLocal.java
package test.ejb;
import javax.ejb.Local;
@Local
public interface HalloDaoLocal {
public String getText();
}
import javax.ejb.Local;
@Local
public interface GrussGottEjbLocal {
public String sayHello(String name);
public String sayHelloTxt(String name);
}
GrussGottEjb.java
package test.ejb;
import javax.ejb.EJB;
import javax.ejb.Stateless;
@Stateless
public class GrussGottEjb implements GrussGottEjbLocal {
@EJB
HalloDaoLocal halloDao;
@Override
public String sayHello(String name) {
return "Hallo " + name;
}
@Override
public String sayHelloTxt(String name) {
String txt = halloDao.getText();
return "Hallo " + name + txt;
}
}
TestGrussGott.java
import javax.ejb.EJB;
/**
return jar;
@Test
4. Download JBoss "jboss-5.1.0.GA"
Dowload the JBoss server from www.jboss.org, and extract it to your favorite location.
On my machine , I extracted jboss to:
As usual, we need to set up PATH and JAVA_HOME system variables for jboss. When you have followed the part 1-2 of this turorial serial, where JBoss 7 is used, you mus have PATH and JAVA_HOME set to your jdk7 installation. This should be changed to a jdk6 location.
Following is the setting on my machine:
6.2 Run tests
When you have followed all the steps till now, with no mistakes, the test results will be :
1. Create a simple Maven project in Eclipse
Follow the section 1 of "EJB3 Integration Test with Arquillian part1-JBoss 7 managed container" to create a new Eclipse project "testarq_jb5_managed". Be sure in step2, to name the ArtifactId as "testarq_jb5_managed".
2. Create project's pom.xml file
As you may remember, for Arquillian with JBoss 7, there is a dependency in pom.xml file called "arquillian-bom". We used this bom dependency to resolve all the Aquillian and JBoss artifacts. But unfortunately for JBoss 5, I could not find such a bom dependency, so all the dependencies in this pom.xml need to be configured "manually".
Create a "pom.xml" file in the "testarq_jb5_managed" project, which we created in section 1. Replace the content of "pom.xml" will the content below:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
found exception. But exclude this lib caused class not found exception so
now first exclude this, and then try introducing a correct javasist lib -->
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>testarg</groupId>
<artifactId>testarq_jb5_1_managed</artifactId>
<version>0.0.1</version>
<description>test arr</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 1.0.3.Final 1.0.0.Alpha5 -->
<version.arquillian_core>1.0.3.Final</version.arquillian_core>
<version.org.jboss.jbossas>5.1.0.GA</version.org.jboss.jbossas>
<version.org.jboss.jbossas_server-manager>1.0.3.GA</version.org.jboss.jbossas_server-manager>
<version.ejb3_api>3.1.0</version.ejb3_api>
</properties>
<repositories>
<!-- Use this repository you could find all jars for jb5. it compiles.
Test runs with error.. -->
<repository>
<id>maven-us.nuxeo.org</id>
<url>https://maven-us.nuxeo.org/nexus/content/repositories/public</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
</plugin>
</plugins>
</build>
<dependencies>
</dependencies>
<profiles>
<profile>
<id>arquillian-jbossas-managed_5_1</id>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-jbossas-managed-5.1</artifactId>
<version>1.0.0.CR3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.jbossas</groupId>
<artifactId>jboss-server-manager</artifactId>
<version>1.0.3.GA</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.jbossas</groupId>
<artifactId>jboss-as-client</artifactId>
<version>5.1.0.GA</version>
<type>pom</type>
<scope>provided</scope>
<!-- it is the javassist:javassist:jar:3.4.GA: , causing method not found exception. But exclude this lib caused class not found exception so
now first exclude this, and then try introducing a correct javasist lib -->
<exclusions>
<exclusion>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.9.0.GA</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<version>${version.arquillian_core}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-container-spi</artifactId>
<version>${version.arquillian_core}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>trove</groupId>
<artifactId>trove</artifactId>
<version>1.0.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
</profiles>
</project>
! Instead of using the default "maven central repository", we have to switch repository to "maven-us.nuxeo.org", as configured in the repositories section of the above "pom.xml" file.
Maven could not find some dependencies in "central maven repository" ( maybe they were removed, or not hosted there at all °_°).
3. Implement source code and test code
As code sample we will take a typical use case in JEE application:
A business layer/class uses a DAO (data access object) to access business data. Here business class and DAO class are both stateless session bean.
To implement and test the above use case, we need to create following classes in the "testarq_jb5_managed" project:
2 for bussiness classes:
GrussGottEjbLocal.java
GrussGottEjb.java
2 for DAO classes:
HalloDaoLocal.java
HalloDao.java
and the test class:
TestGrussGott.java
Now the "testarq_jb5_managed" project in Eclipse will looks like:
Replace the content of java files with following contents:
HalloDaoLocal.java
package test.ejb;
import javax.ejb.Local;
@Local
public interface HalloDaoLocal {
public String getText();
}
HalloDao.java
package test.ejb;
import javax.ejb.Stateless;
@Stateless
public class HalloDao implements HalloDaoLocal {
@Override
public String getText() {
return "!";
}
}
!
"HalloDao" is still not realy a DAO, it is not equipted with any persistence or database utilities.
Persistence with JPA / Hibernate will be shown in the part 4 of this serial. For now, we just want to simulate calling a session bean in an other session bean, therefore, no accessing database is really necessary.
"HalloDao" is still not realy a DAO, it is not equipted with any persistence or database utilities.
Persistence with JPA / Hibernate will be shown in the part 4 of this serial. For now, we just want to simulate calling a session bean in an other session bean, therefore, no accessing database is really necessary.
GrussGottEjbLocal.java
package test.ejb;import javax.ejb.Local;
@Local
public interface GrussGottEjbLocal {
public String sayHello(String name);
public String sayHelloTxt(String name);
}
GrussGottEjb.java
package test.ejb;
import javax.ejb.EJB;
import javax.ejb.Stateless;
@Stateless
public class GrussGottEjb implements GrussGottEjbLocal {
@EJB
HalloDaoLocal halloDao;
@Override
public String sayHello(String name) {
return "Hallo " + name;
}
@Override
public String sayHelloTxt(String name) {
String txt = halloDao.getText();
return "Hallo " + name + txt;
}
}
TestGrussGott.java
package test.ejb;
import javax.ejb.EJB;
import junit.framework.Assert;
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.runner.RunWith;
/**
* @author he
*
*/
@RunWith(Arquillian.class)
public class TestGrussGott {
@Deployment
public static JavaArchive createDeployment() {
JavaArchive jar = ShrinkWrap.create(JavaArchive.class, "hgrussEjb.jar");
jar.addClass(GrussGottEjbLocal.class).addClass(GrussGottEjb.class);
jar.addClass(HalloDao.class).addClass(HalloDaoLocal.class);
//jar.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
System.out.println(jar.toString(true));
return jar;
}
@EJB
GrussGottEjbLocal grusEjb;
@Test
public void sayHallo() {
String result = grusEjb.sayHello("hehe");
Assert.assertEquals("Hallo hehe", result);
}
@Test
public void sayHalloTxt() {
String result = grusEjb.sayHelloTxt("hehe");
Assert.assertEquals("Hallo hehe!", result);
}
}
! In the "TestGrussGott.java" the line for "beans.xml" is commented out. This line is put here only to show, that unlike Arquillian test with JBoss 7 container, for Arquillian test with JBoss 5 container, the "beans.xml" is not needed.
Dowload the JBoss server from www.jboss.org, and extract it to your favorite location.
On my machine , I extracted jboss to:
/home/he/jboss-5.1.0.GA
As usual, we need to set up PATH and JAVA_HOME system variables for jboss. When you have followed the part 1-2 of this turorial serial, where JBoss 7 is used, you mus have PATH and JAVA_HOME set to your jdk7 installation. This should be changed to a jdk6 location.
Following is the setting on my machine:
> export JAVA_HOME=/usr/java/jdk1.6.0_32/
> export PATH=/usr/java/jdk1.6.0_32/bin:$PATH
5. arquillian.xml
We still need to tell Arquillian where to find JBosss installation, and which JBoss instance is to be managed by Arquillian.
Create an "arquillian.xml" in the folder"src/test/resources" with the content below:
<?xml version="1.0" encoding="UTF-8"?>
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://jboss.org/schema/arquillian"
xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<container qualifier="jboss5" default="true">
<configuration>
<property name="jbossHome">path_2_your_jboss/jboss-5.1.0.GA</property>
<property name="profileName">default</property>
</configuration>
</container>
</arquillian>
6. Run the tests
We have learned how to run the Maven test in Eclipse. Now we will try runing the tests using command line.
6.1 Set system properties "PATH" and "JAVA_HOME"
Make sure you have correctly set "PATH" and "JAVA_HOME". In case of linux you could check this using following command:
> which java
/usr/java/jdk1.6.0_32/bin/java
> echo $JAVA_HOME
/usr/java/jdk1.6.0_32/
Command to set the properties:
export JAVA_HOME=/usr/java/jdk1.6.0_32/
export PATH=/usr/java/jdk1.6.0_32/bin:$PATH
6.2 Run tests
Run Maven tests using following command:
> mvn clean test -Parquillian-jbossas-managed_5_1
To find out more details about the test failure, we will have a close look at the maven/surefile test report, this is the "test.ejb.TestGrussGott.txt" in /target/surefile-reports/:
But, when the "hgrussEjb.jar" is deployed by Arquillian in JBoss, it is bund to the following JNDI as shown in JBoss "server.log":
Now problem is clear: using @EJB only is not enough!
The solution is actually easy. In the "TestGrussGott,java", just change the annotation from:
to :
@EJB(mappedName="test/GrussGottEjb/local")
8. Run test again
...
java.lang.IllegalStateException: java.lang.RuntimeException: Error creating MBeanProxy: jboss.web:name=http-localhost-8080,type=GlobalRequestProcessor
...
-------------------------------------------------------------------------------
Test set: test.ejb.TestGrussGott
-------------------------------------------------------------------------------
Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 124.531 sec <<< FAILURE!
sayHallo(test.ejb.TestGrussGott) Time elapsed: 1.442 sec <<< ERROR!
java.lang.NullPointerException
at test.ejb.TestGrussGott.sayHallo(TestGrussGott.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
....
The Exception above says that in the "TestGrussGott,java", we have a problem on the line :
...
@Test
@Test
public void sayHallo() {
String result = grusEjb.sayHello("hehe");
Assert.assertEquals("Hallo hehe", result);
}
...
...
Here we have a NullPointerException for the object "grusEjb", i.e. "grusEjb" is null. This objected was injected in test class using @EJB annotation:
@EJB
GrussGottEjbLocal grusEjb;
We remember in the test cases using JBoss 7, we have always been doing like this, why this time failed?
Actually, our problem lies really in this place, in the @EJB annotation!
To put it short:
To put it short:
Arquillian can not find the "GrussGottEjb" using only @EJB, althrough the bean is deployed in JBoss.
7. Finding the EJB with annotation
When only @EJB is used, Arquillian tries to look up the "GrussGottEjb" session bean using following JNDI (could be seen in JBoss server.log):
....
FINE [org.jboss.arquillian.test.spi.TestEnricher]
FINE [org.jboss.arquillian.test.spi.TestEnricher]
(http-localhost%2F127.0.0.1-8080-2) Could not lookup @javax.ejb.EJB(beanName=, mappedName=, beanInterface=class java.lang.Object, description=, name=),
other Enrichers might, move on. Exception: No EJB found in JNDI,
tried the following names: java:global/test.ear/test/GrussGottEjbLocalBean,
java:global/test.ear/test/GrussGottEjbLocal,
java:global/test/GrussGottEjbLocal,
java:global/test/GrussGottEjbLocalBean,
java:global/test/GrussGottEjbLocal/no-interface,
test/GrussGottEjbLocalBean/local,
test/GrussGottEjbLocalBean/remote,
test/GrussGottEjbLocal/no-interface,
GrussGottEjbLocalBean/local,
GrussGottEjbLocalBean/remote,
GrussGottEjbLocal/no-interface,
ejblocal:test.ejb.GrussGottEjbLocal,
test.ejb.GrussGottEjbLocal,
....
....
But, when the "hgrussEjb.jar" is deployed by Arquillian in JBoss, it is bund to the following JNDI as shown in JBoss "server.log":
...
jndi:test/GrussGottEjb/local-test.ejb.GrussGottEjbLocal
jndi:test/GrussGottEjb/local
jndi:test/GrussGottEjb/remote
...
...
The solution is actually easy. In the "TestGrussGott,java", just change the annotation from:
@EJB
GrussGottEjbLocal grusEjb;
to :
@EJB(mappedName="test/GrussGottEjb/local")
GrussGottEjbLocal grusEjb;
8. Run test again
Now run the test again:
> mvn clean test -Parquillian-jbossas-managed_5_1
And you would see in the console:
9. Troubleshooting
9.1 Exception
....
Failed to collect dependencies for....
...
Could not transfer artifact org.jboss.aop:jboss-aop-aspects:pom:2.1.1.GA from/to repository.jboss.org (http://repository.jboss.org/maven2):
Access denied to: http://repository.jboss.org/maven2/org/jboss/aop/jboss-aop-aspects/2.1.1.GA/jboss-aop-aspects-2.1.1.GA.pom,
Failed to collect dependencies for....
...
Could not transfer artifact org.jboss.aop:jboss-aop-aspects:pom:2.1.1.GA from/to repository.jboss.org (http://repository.jboss.org/maven2):
Access denied to: http://repository.jboss.org/maven2/org/jboss/aop/jboss-aop-aspects/2.1.1.GA/jboss-aop-aspects-2.1.1.GA.pom,
...
This indicates that dependencies could not be downloaded from Maven central repository. Check your pom.xml file in section 2 of this turorial, make sure you have configured /customized Maven repository (for example "maven-us.nuxeo.org"" ).
9.2 When you observer error information like:
Error in Console:
Tests in error:
test.ejb.TestGrussGott: Could not start remote container
Error in "test.ejb.TestGrussGott.tx":
org.jboss.arquillian.container.spi.client.container.LifecycleException: Could not start remote container
...
Caused by: java.io.IOException: Server failed to start; see logs. exit code: 0...
And Error in JBoss "server.log"
Failed to get property value for bean: org.jboss.web.tomcat.service.management.ConnectorBean, property: bytesSentjava.lang.IllegalStateException: java.lang.RuntimeException: Error creating MBeanProxy: jboss.web:name=http-localhost-8080,type=GlobalRequestProcessor
...
Caused by: java.lang.RuntimeException: Error creating MBeanProxy: jboss.web:name=http-localhost-8080,type=GlobalRequestProcessor
The reason for the above errors is very likely running JBoss with the wrong Java version. So please make sure to run JBoss with jdk6, anot NOT jdk7. Check PATH and JAVA_HOME of your system again.
No comments:
Post a Comment