Monthly Archives: May 2015

Arquillian y GlassFish: portar ‘Hola Mundo’ desde TomEE

Por ahora hemos visto cómo efectuar un test Hola Mundo con Arquillian y WildFly, y cómo portar dicho test a Arquillian + TomEE.

Hoy veremos cómo ejecutar ese test contra GlassFish, usando su adaptador managed.

1.Configuración de dependencias

En teoría, lo único que debería cambiar a nivel de dependencias son las librerías de arquillian para GlassFish (cambio #1).

Modificaremos build.gradle para utilizar org.jboss.arquillian.container:arquillian-glassfish-managed-3.1:1.0.0.Final-SNAPSHOT, como sigue:

   // *****************************************************************************
   // GlassFish managed
   testRuntime 'org.jboss.arquillian.container:arquillian-glassfish-managed-3.1:1.0.0.Final-SNAPSHOT'

2. Código

El mismo que para WildFly y para TomEE.

3. Configuración de Runtime

Aunque tocaría ahora, ya hemos cambiado las dependencias de tiempo de ejecución para tests más arriba.

Debemos cambiar el archivo arquillian.xml para configurar el servidor managed de GlassFish (cambio #2), que quedará como sigue:

<?xml version="1.0" encoding="UTF-8"?>
<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="glassfish-managed" default="true">
      <configuration>
         <property name="glassFishHome">/home/pagdev/pagde/tool/glassfish-4.1/</property>
      </configuration>
   </container>
</arquillian>

La única propiedad obligatoria de esta configuración es glassFishHome, que debe apuntar al directorio de instalación de GlassFish.

4. Ejecutar tests

Se ejecutan exactamente igual:

gradle test --tests *Test

Notas

Tan solo hemos tenido que hacer dos cambios para poder lanzar el test más simple posible usando un bean EJB.

Gradle tardó en ejecutar el test contra GlassFish managed alrededor de 18 segundos, y contra WildFly managed sobre los 11 segundos, y a lo largo de numerosas ejecuciones los tiempor variaron no más de 2 segundos. Contra Tomcat embedded, los tests se ejecutaron en torno a 6 o 7 segundos.

Software utilizado

Esto ha sido probado con GlassFish 4.1 y Arquillian 1.1.8, usando Gradle 2.3.

Arquillian y TomEE: portar ‘Hola Mundo’ de WildFly a TomEE

En teoría, Arquillian permite escribir tests de integración para varios servidores utilizando el mismo código y con unos cambios mínimos de configuración.

En este blog mi objetivo es usar Arquillian con TomEE en lugar de WildFly, y ver qué cambios debemos realizar para ejecutar el mismo test Hola Mundo que ya vimos en WildFly.

El objetivo es detallar todos y cada uno los cambios de configuración entre TomEE embedded y WildFly embedded.

1.Configuración de dependencias

Dado que no usamos ninguna funcionalidad específica de ningún servidor de aplicaciones, las dependencias de compilación y de test son las mismas que en el proyecto para WildFly.

En teoría, lo único que debería cambiar a nivel de dependencias son las librerías del runtime de Tomee (cambio #1), necesarias para arrancar y ejecutar TomEE en lugar de WildFly.

Modificaremos build.gradle para utilizar org.apache.openejb:arquillian-tomee-embedded:1.7.1, como sigue:

   // *****************************************************************************
   // TomeePlume: embedded
   testRuntime 'org.apache.openejb:arquillian-tomee-embedded:1.7.1'

Sin embargo, en la práctica, al ejecutar los test, nos encontramos con un error, java.lang.ClassFormatError, que se soluciona cambiando la dependencia de la API de JEE6 a javax:javaee-api:6.0 (cambio #2) para TomEE.

Como WildFly funciona perfectamente contra esta dependencia, este es más bien un cambio a hacer a la configuración de WildFly que a la de TomEE.

2. Código

El mismo que para WildFly.

3. Configuración de Runtime

Aunque tocaría ahora, ya hemos cambiado las dependencias para ejecutar TomEE en lugar de WildFly más arriba.

Por supuesto, debemos cambiar el archivo arquillian.xml para configurar el servidor embedded de Tomee (cambio #3), que quedará como sigue:

<?xml version="1.0" encoding="UTF-8"?>
<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="tomee" default="true">
      <configuration>
      </configuration>
   </container>
</arquillian>

Y, sí, no hace falta configurar ningún parámetro para usar el TomEE embedded.

Otra cosa a tener en cuenta es que en la versión de WildFly con el adaptador embedded era obligatorio pasar a la máquina virtual del servidor el parámetro java.util.logging.manager, seleccionando el log manager de WildFly. Pero dicho gestor no está disponible en TomEE, por lo que no arrancará.

Solución: no pasar el parámetro java.util.logging.manager al runtime de TomEE (cambio #4).

4. Ejecutar tests

Se ejecutan exactamente igual.

En resumen

Hemos tenido que hacer cuatro cambios para poder lanzar el test más simple posible usando un bean EJB.

En realidad, si actualizamos la versión de WildFly para que use la dependencia org.apache.openejb:javaee-api:6.0-4 como API de JEE 6, con la que funciona perfectamente, el número de cambios es de 3, todos ellos triviales.

No está nada mal, ¿no?

Notas

Como nota aparte, comentar que Gradle tardó en ejecutar el test contra TomEE 5.856 segundos. El mismo test, lanzado contra WildFly con la configuración standalone.xml tardó 9.443 segundos.

Los tiempos en numerosas ejecuciones se mantuvieron siempre en torno a estos valores, con variaciones de no más de 1 segundo. Es una diferencia notable y que vale la pena mencionar, pero tampoco le daría mucha importancia, ya que el nuestro no es un escenario realista.

Software utilizado

Esto ha sido probado con TomeePlume 1.7.1 y Arquillian 1.1.8, usando Gradle 2.3.

Arquillian y WildFly: test ‘Hola Mundo’

Arquillian permite crear tests de integración con servidores/contenedores web y JEE como WildFly (o Tomcat), de forma bastante sencilla.

Para trabajar con un servidor, Arquillian usa adaptadores de contenedor, que permiten arrancar y parar los contenedores. Estos pueden ser de tres tipos: embebidos, gestionados, y remotos (embedded, managed y remote, a partir de ahora).

Para este Hola mundo usaremos el adaptador embedded, y dejaremos para otro artículo la discusión de qué ventajas e inconvenientes tiene cada tipo de adaptador y cuándo usar cada uno.

1. Configuración de dependencias

Para compilar los tests necesitaremos JUnit y Arquillian: con tan solo incluir junit:junit:4.11 y org.jboss.arquillian.junit:arquillian-junit-container:1.1.8.Final en build.gradle se incluirán todos los demás jars necesarios, especialment las dependencias de Arquillian.

Para ejecutar los tests, debemos incluir un adaptador de contenedor de WildFly, que Arquillian usará para arrancar y parar el contenedor contra el que se ejecutará el test. Como usaremos el contenedor embedded de WildFly, debemos incluir org.wildfly:wildfly-arquillian-container-embedded:8.2.0.Final en la lista de dependencias.

Por último, para que Gradle pueda encontrar algunas de estas dependencias deberemos añadir un repositorio de JBoss a nuestro build.gradle, que una vez hecho todo esto quedará como sigue:

apply plugin: 'java'

sourceCompatibility = 1.6

repositories {
  mavenCentral()
  maven {
    url "http://repository.jboss.org/nexus/content/groups/public-jboss"
  }
}

dependencies {
  compile 'javax:javaee-api:6.0'
  testCompile 'junit:junit:4.11',
    'org.jboss.arquillian.junit:arquillian-junit-container:1.1.8.Final'
  testRuntime 'org.wildfly:wildfly-arquillian-container-embedded:8.2.0.Final'
}

test {
  // Si no se especifica el log manager con el adaptador embedded de WildFly 8.2,
  // no arrancara correctamente
  systemProperties 'java.util.logging.manager': 'org.jboss.logmanager.LogManager'
}

2. Código

Para demostrar cómo implementar y ejecutar tests sencillos crearemos un stateless session bean, MyStatelessEjb, que simplemente suma dos números:

import javax.ejb.Stateless;

@Stateless
public class MyStatelessEjb {
   public int sum(int a, int b) {
      return a + b;
   }
}

Para hacer un test JUnit con Arquillian necesitaremos un runner de JUnit especial, incluido con Arquillian, para lo que anotaremos la clase de test con @RunWith(Arquillian.class).

También debemos especificar la configuración básica de la aplicación, para que el test se pueda ejecutar en el contexto adecuado. Debemos indicar dónde están los .class necesarios, si vamos a crear un war u otra cosa, quizá incluir un archivo de configuración como persistence.xml, etc.

Para ello se debe crear un método anotado con @Deployment, que utilizará la clase ShrinkWrap para llevar a cabo toda esta tarea de configuración.

El código resultante para hacer el test será como sigue:

@RunWith(Arquillian.class)
public class MyStatelessEjbTest {
   @EJB
   private MyStatelessEjb ejb;

   @Deployment
   public static Archive<?> createTestArchive() {
       return ShrinkWrap.create(WebArchive.class)
               .addPackage(MyStatelessEjb.class.getPackage());
   }

   @Test
   public void testSum() {
      Assert.assertEquals(5, ejb.sum(6,-1));
   }
}

Por lo demás, los tests son tests JUnit normales y corrientes, como se puede ver con testSum. Nótese que este test usa nuestro bean, que se ha inyectado en el test con @EJB, y que el propio contenedor WildFly gestiona.

3. Configuración de Runtime

Llegados a este punto, la aplicación compilará, pero aún es necesario dar unos pasos extra para que la aplicación arranque y podamos ejecutar los tests.

Las librerías adicionales necesarias en tiempo de ejecución ya las hemos incluido en un paso anterior, pero aún debemos configurar Arquillian. Esto se hace mediante arquillian.xml, que ubicaremos en el directorio src/test/resources del proyecto. Quedará como sigue:

<?xml version="1.0" encoding="UTF-8"?>
<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="jboss-embedded" default="true">
    <configuration>
      <property name="jbossHome">/home/pagdev/pagde/tool/wildfly-8.2.0.Final</property>
      <property name="modulePath">/home/pagdev/pagde/tool/wildfly-8.2.0.Final/modules</property>
      <property name="serverConfig">standalone-full.xml</property>
    </configuration>
  </container>
</arquillian>

Aquí usamos la propiedad jbossHome, requerida, para indicar cuál es el directorio donde se halla JBoss (como JBOSS_HOME).

Esta versión del adaptador también requiere que se le pase el parámetro modulePath, que es donde se encuentran los módulos utilizables de JBoss. Por defecto están en el subdirectorio modules en JBoss. Es curioso que este parámetro sea obligatorio, dado que podrían utilizar un valor por defecto sin problemas.

También he añadido el parámetro serverConfig, que nos permite especificar qué configuración de servidor vamos a utilizar, y que no es requerido.

4. Ejecutar tests

Desafortunadamente necesitamos un pequeño workaround para un bug del adaptador embedded. Es necesario pasarle al contenedor WildFly arrancado por Arquillian el parámetro java.util.logging.manager, para el que simplemente utilizaremos el LogManager por defecto de WildFly. Esto es lo que hace el siguiente fragmento de build.gradle:


test {
  systemProperties 'java.util.logging.manager':
         'org.jboss.logmanager.LogManager'
}

Una alternativa a esto sería llamar a gradle desde la línea de comando pasándole ese parámetro. Para lanzar todos los tests del proyecto, por ejemplo, tendríamos la siguiente línea de comandos:

gradle test -Djava.util.logging.manager=org.jboss.logmanager.LogManager --tests *Test

Con la configuración actual de build.gradle, podemos lanzar el test con

gradle test --tests *Test

Por otro lado, si ejecutamos los tests desde Eclipse y no usando Gradle desde la línea de comandos, habrá que indicarle al launcher correspondiente que pase a la VM el parámetro -Djava.util.logging.manager=org.jboss.logmanager.LogManager.

Si queremos ejecutar estos tests desde la línea de comandos, y depurarlos con Eclipse, vale la pena consultar este otro artículo.

Software utilizado

Esto ha sido probado con WildFly 8.2 y Arquillian 1.1.8, usando Gradle 2.3.

Debugging tests with Gradle and Eclipse

If you use Gradle to run your tests, and are an Eclipse user but the project you are working in is not an Eclipse project, you might think that you are out of luck when it comes to debugging. But that’s not the case, you can use Eclipse to debug a test you can launch with Gradle.

Step #1: launch the test in Gradle

Launch your test with Gradle. Supposing your test is x.y.MyTest, run Gradle as follows:

gradle test --debug-jvm --tests x.y.MyTest

Because you are using the –debug-jvm thing, Gradle will wait for a debugger to get attached, as shown below:

Gradle waiting for a debugger to be attached

1. Launch the test with Gradle

STEP #2: create a Java launcher for remote debugging

To atttach the Eclipse debugger, open Eclipse and go to Run|Debug Configurations…, and create a new launcher: select the Remote Java Application type. The key point here is to use the same port Gradle is using, in this case 5005. I have called this debug launcher Gradle, debug, and have configured it as follows:

Configuring Eclipse to debug Gradle tests

2. Configure Eclipse to debug the Gradle test

Step #3: tell the launcher where to find the source code

To tell Eclipse where to find the source code, go to the Source tab in the launcher configuration. Click Add…, and choose the directory for your Java source code.

3. Tell Eclipse where to find the source code

3. Tell Eclipse where to find the source code

Debug!

Now you can use Eclipse to place some breakpoints, step through your code, etc. Just open the launcher and click Debug. Voilá!

What else?

I have tested this with Gradle 2.3 and Eclipse Luna (4.4.2).