Testing WildFly Applications with Arquillian and JUnit 5
In this guide you will learn how to setup your project for testing with Arquillian and JUnit 5. We will use the arquillian-junt5 example project in this guide.
Prerequisites
To complete this guide, you need:
-
Roughly 15 minutes
-
JDK 17+ installed with
JAVA_HOME
configured appropriately -
Apache Maven 3.9+
Add JUnit and Arquillian Dependencies
In order to use JUnit and Arquillian for your tests, you need to update the Maven pom.xml
. The best practice is to
import the Arquillian, JUnit 5 and WildFly Arquillian BOM’s.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-bom</artifactId>
<version>${version.jakarta.ee}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-bom</artifactId>
<version>${version.org.jboss.arquillian}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.wildfly.arquillian</groupId>
<artifactId>wildfly-arquillian-bom</artifactId>
<version>${version.org.wildfly.arquillian}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${version.org.junit}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
You then need a minimum of the following dependencies.
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.junit5</groupId>
<artifactId>arquillian-junit5-container</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wildfly.arquillian</groupId>
<artifactId>wildfly-arquillian-container-managed</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
In this section we will work on writing a test for our application. We will assume here you already have experience writing Jakarta EE applications for WildFly. For the purpose of this test, we will use the wildfly-maven-plugin to provision a server for testing.
Configure POM for Provisioning
<build>
<plugins>
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>${version.wildfly-maven-plugin}</version>
<configuration>
<jboss-home>${jboss.home}</jboss-home>
<provisioning-dir>${jboss.home}</provisioning-dir>
<feature-packs>
<feature-pack>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-ee-galleon-pack</artifactId>
</feature-pack>
</feature-packs>
<channels>
<channel>
<manifest>
<groupId>org.wildfly.channels</groupId>
<artifactId>wildfly-ee</artifactId>
</manifest>
</channel>
</channels>
<layers>
<layer>ee-core-profile-server</layer>
<layer>jpa</layer>
<layer>h2-default-datasource</layer>
<layer>transactions</layer>
</layers>
<galleon-options>
<jboss-fork-embedded>true</jboss-fork-embedded>
</galleon-options>
</configuration>
<executions>
<execution>
<id>provision-server</id>
<goals>
<goal>provision</goal>
</goals>
<phase>process-test-resources</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
The above configuration will provision a server based with Jakarta EE Core Profile specifications, Jakarta Persistence, Jakarta Transactions and the default H2 data source. The layers can be removed to provision a full WildFly server.
The provisioning is bound to the process-test-resources
phase. This is the last phase before the test
phase which
is when our tests will be executed by default. We need a server before we can use Arquillian for our tests.
Writing Tests
Now that our POM is configured, we can write a test for our application. The first step is to tell JUnit 5 we want
to extend the functionality with Arquillian. The simplest approach is to annotate your test with @ArquillainTest
. The
other option is to annotate the test with @ExtendWith(ArquillianExtension.class)
.
@ArquillianTest
public class AddTaskResourceTest {
}
Client Test
Arquillian can run both in the container or as a client. For the first example we will run as a client. When running as
a client the test runs outside the container. The simplest way to run as a client is to use the @RunAsClient
annotation.
@ArquillianTest
@RunAsClient
public class AddTaskResourceTest {
}
The next thing Arquillian needs is a deployment. You can use Shrinkwrap to create a deployment.
Note
|
Shrinkwrap is a transitive dependency of Arquillian. |
@ArquillianTest
@RunAsClient
public class AddTaskResourceTest {
@Deployment
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class)
.addPackages(true, "org.wildfly.guide.testing")
.addAsResource("META-INF/persistence.xml")
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}
}
We can now add a test method using standard JUnit 5 testing strategies.
@ArquillianTest
@RunAsClient
public class AddTaskResourceTest {
@ArquillianResource
private URI uri;
@Deployment
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class)
.addPackages(true, "org.wildfly.guide.testing")
.addAsResource("META-INF/persistence.xml")
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}
@Test
public void addTask() {
final Task toAdd = new Task();
toAdd.setSummary("This is a test task");
toAdd.setDescription("This the test tasks description");
try (
Client client = ClientBuilder.newClient();
Response createdResponse = client.target(UriBuilder.fromUri(uri).path("api/task/")).request()
.post(Entity.json(toAdd))) {
Assertions.assertEquals(Response.Status.CREATED, createdResponse.getStatusInfo(),
() -> String.format("Invalid status: %s", createdResponse.readEntity(String.class)));
// We should have the location
try (Response response = client.target(createdResponse.getLocation()).request().get()) {
Assertions.assertEquals(Response.Status.OK, response.getStatusInfo(),
() -> String.format("Invalid status: %s - %s", createdResponse.readEntity(String.class),
createdResponse.getLocation()));
final Task resolvedTask = response.readEntity(Task.class);
Assertions.assertNotNull(resolvedTask);
Assertions.assertTrue(resolvedTask.getId() > 0,
() -> String.format("Expected the task to have an ID greater than 0: %s", resolvedTask.getId()));
}
}
}
}
Note
|
The @ArquillianResource can be used in inject various resources from Arquillian and WildFly Arquillian. In this
example we inject a URI for the deployment.
|
In Container Test
In container tests have a similar structure to client based test. However, the test itself runs inside the container. This allows you to use CDI to inject beans into your test for example.
@ArquillianTest
@RequestScoped
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TaskRegistryTest {
@Inject
private TaskRegistry taskRegistry;
@Deployment
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class)
// Note for this test we don't use the REST endpoints so we don't need the REST resources
.addClasses(TaskRegistry.class,
Priority.class,
Task.class,
Producers.class,
TaskListener.class)
.addAsResource("META-INF/persistence.xml")
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}
@Test
@Order(1)
public void addTask(final TestInfo testInfo) {
final Task task = new Task();
task.setAdded(Instant.now());
task.setDescription("This is a test task from " + testInfo.getTestMethod()
.map(Method::getName)
.orElse("<unknown>"));
task.setPriority(Priority.IMPORTANT);
task.setSummary("Test summary");
final var addedTask = taskRegistry.add(task);
Assertions.assertEquals(task, addedTask);
}
}
What’s next?
Using JUnit 5 and Arquillian for testing offers several options for testing your application with WildFly. WildFly Arquillian includes some additional utilities not discussed in this guide such as the ability to configure server settings before your test executes. An advanced guide will dig deeper into the additional options for using Arquillian on WildFly.