Over a million developers have joined DZone.

Testing EJBs with Swarm and Arquillian

Learn how to write standard unit tests against EJBs using Arquillian and WildFly Swarm.

· DevOps Zone

The DevOps Zone is brought to you in partnership with Sonatype Nexus. The Nexus Suite helps scale your DevOps delivery with continuous component intelligence integrated into development tools, including Eclipse, IntelliJ, Jenkins, Bamboo, SonarQube and more. Schedule a demo today

An issue faced by many Java EE developers is creating unit tests that make use of all the functionality provided by an application server. Often developers have been forced to mock up any functionality provided by the application server using libraries like Mockito in order to validate business logic, which gets the job done, but is quite a bit of work.

Arquillian is a JBoss project that provides developers with a real Java EE environment in which to test their business objects. Arquillian takes care of building up and shutting down your environment, and then running your tests either inside the environment (think injecting EJBs or CDI beans into a unit test), as as an external client (as you would do when testing external rest interfaces).

Arquillian and Swarm share a lot of functionality via the Shinkwrap library. Swarm uses Shrinkwrap to build up Java artifacts for deployment within the Swarm provided application server. Arquillian does the same for Java artifacts to be run as part of a test. Developers using Swarm will find that they have already done most of the work to create an Arquillian test environment.

To demonstrate the use of Aqruillian with Swarm, we’ll add a simple test to the EJB example that we created in this article.

To make use of Arquillian, we need some additional dependencies:

  • org.wildfly.swarm:arquillian
  • org.jboss.arquillian.junit:arquillian-junit-container
buildscript {
    repositories {
        mavenLocal()
        mavenCentral()
    }

    dependencies {
        classpath "org.wildfly.swarm:wildfly-swarm-plugin:1.0.0.Beta8"
        classpath "io.spring.gradle:dependency-management-plugin:0.5.6.RELEASE"
    }
}

group 'com.matthewcasperson'
version '1.0-SNAPSHOT'

apply plugin: 'java'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'wildfly-swarm'

sourceCompatibility = 1.8

swarm {
    mainClassName = 'com.matthewcasperson.swarmdemo.Main'
}

def swarmVersion = '1.0.0.Beta8'
repositories {
    mavenCentral()
    mavenLocal()
    maven {
        url 'http://repository.jboss.org/nexus/content/groups/public-jboss'
    }
    maven {
        url 'https://maven.repository.redhat.com/nexus/content/repositories/public'
    }
}

dependencyManagement {
    imports {
        mavenBom "org.wildfly.swarm:bom:$swarmVersion"
    }
}


dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'
    testCompile 'org.wildfly.swarm:arquillian'
    testCompile 'org.jboss.arquillian.junit:arquillian-junit-container'

    compileOnly 'javax:javaee-api:7.0'

    compile 'org.wildfly.swarm:bootstrap'
    compile 'org.wildfly.swarm:ejb'

}

// For heroku
task stage {
    dependsOn build
}

Right now, the Swarm integration with Arquillian has a hard coded dependency on a Maven pom.xml file. We’ll continue to build our app and run the tests with Gradle, but we are forced to add a pom.xml file to satisfy the WildFlySwarmObserver class, which has this code:

// Gather test and provided dependencies
final ShrinkwrapArtifactResolvingHelper resolvingHelper = ShrinkwrapArtifactResolvingHelper.defaultInstance();
final MavenResolvedArtifact[] deps =
     resolvingHelper.withResolver(r -> r.loadPomFromFile("pom.xml") // Not Gradle friendly :(
        .importDependencies(ScopeType.TEST, ScopeType.PROVIDED)
        .resolve()
        .withTransitivity()
        .asResolvedArtifact());

I created the pom.xml file using the online Swarm project generator.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>demo</artifactId>
  <name>Wildfly Swarm Example</name>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <properties>
    <version.wildfly.swarm>1.0.0.Beta8</version.wildfly.swarm>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <failOnMissingWebXml>false</failOnMissingWebXml>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.wildfly.swarm</groupId>
        <artifactId>bom</artifactId>
        <version>${version.wildfly.swarm}</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <finalName>demo</finalName>
    <plugins>
      <plugin>
        <groupId>org.wildfly.swarm</groupId>
        <artifactId>wildfly-swarm-plugin</artifactId>
        <version>${version.wildfly.swarm}</version>
        <executions>
          <execution>
            <goals>
              <goal>package</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <!-- Java EE 7 dependency -->
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <version>7.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- Wildfly Swarm Fractions -->
    <dependency>
      <groupId>org.wildfly.swarm</groupId>
      <artifactId>ejb</artifactId>
    </dependency>
    <dependency>
      <groupId>org.wildfly.swarm</groupId>
      <artifactId>cdi</artifactId>
    </dependency>
    <dependency>
      <groupId>org.wildfly.swarm</groupId>
      <artifactId>arquillian</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

As a side note, I could only get the test to work when I included the Swarm CDI dependency in the Maven pom.xml file, but not in the Gradle gradle.build file. CDI is used by Arquillian to do injection of EJBs, but I still don’t know why listing the dependency in the gradle.build file would cause issues. I’ll put this down to the fact that Swarm Arquillian doesn’t play well with Gradle just yet.

For the sake of convenience, I have moved the code that generates the Shinkwrap artifact into its own class. We’ll share this code between the application and the Arquillian unit tests.

package com.matthewcasperson.swarmdemo;

import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.wildfly.swarm.spi.api.ArtifactLookup;
import org.wildfly.swarm.spi.api.JARArchive;

import java.util.List;

/**
 * Created by matthewcasperson on 7/05/2016.
 */
public class ArchiveBuilder {
    public Archive buildArchive() throws Exception {
        final JARArchive ejbArchive = ShrinkWrap.create(JARArchive.class);
        ejbArchive.addClass(MyEJB.class);

        /*
            Merge in the dependencies that the warm build plugin included in the Swarm UberJar
            into an EJB UberJar. This gives us a self contained EJB JAR file that Swarm can then
            deploy and run.
         */
        final List<JavaArchive> artifacts = ArtifactLookup.get().allArtifacts(new String[]{"org.wildfly.swarm"});
        for (final JavaArchive javaArchive : artifacts) {
            ejbArchive.merge(javaArchive);
        }

        return ejbArchive;
    }
}

Now the test itself. You’ll notice that this there is very little about this unit test that you wouldn’t see in a test of plain Java objects. The major differences are:

  • We have integrated Arquillian into the test lifecycle with the @RunWith annotation.
  • We have annotated a method with @Deployment that returns the Shinkwrap artifact that will be deployed as part of the test. This deployment returns the same Shinkwrap artifact that Swarm deploys when it is run, which is quite convenient for us.

The important thing to take notice of in this test class is that we have injected the EJB directly. This shows of the power of Arquillian, as it gives developers the ability to test real Java EE objects with all their additional abilities inside a standard unit test class.

Our actual test is very basic, and simply validates a method that always returns true. Obviously your tests would be a little more meaningful, but for our purposes we just want to demonstrate calling an EJB inside a test.

package com.matthewcasperson.swarmdemo;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

import javax.ejb.EJB;

/**
 * Created by matthewcasperson on 7/05/2016.
 */
@RunWith(Arquillian.class)
public class SwarmTest {
    @EJB
    private MyEJB myEjb;

    @Deployment
    public static Archive createDeployment() throws Exception {
        return new ArchiveBuilder().buildArchive();
    }

    @Test
    public void testDoingSomeEnterprisyThing() {
        Assert.assertTrue(myEjb.doSomeEnterprisyThing());
    }
}

The combination of Swarm, Arquillian and JUnit gives developers a very powerful environment to validate code in. There is no need for proxies and mocking as the complete Java EE environment is exposed to you tests, which is a huge time saver. I also found that being able to share Shinkwrap artifacts between my application and the unit tests removed one of the bigger burdens that Arquillian users face.

Download the source code for this article at GitHub.

The DevOps Zone is brought to you in partnership with Sonatype Nexus. Use the Nexus Suite to automate your software supply chain and ensure you're using the highest quality open source components at every step of the development lifecycle. Get Nexus today

Topics:
java ,maven ,dependency ,cdi ,unit test ,application server ,gradle

Published at DZone with permission of Matthew Casperson, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}