Skip to content

Commit e7bdcef

Browse files
authored
Merge pull request #721 from jamezp/arq-junit5
[636] Add a guide for Arquillian with JUnit 5
2 parents 61aad11 + 91e37b4 commit e7bdcef

File tree

3 files changed

+296
-1
lines changed

3 files changed

+296
-1
lines changed

_data/guides.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ categories:
1616
- title: Deploying WildFly using Ansible
1717
url: /guides/automate-with-ansible
1818
description: Learn how to automate WildFly deployments with Ansible.
19+
- title: Testing with Arquillian and JUnit 5
20+
url: /guides/testing-arquillian-junit5
21+
description: Learn how to write JUnit 5 tests using Arquillian for Jakarta EE based applications.
1922
- category: Datasources
2023
cat-id: datasources
2124
guides:

_sass/global.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ h2 {
8080
h3 {
8181
font-size: 2rem;
8282
line-height: 2rem;
83-
font-weight: 700;
83+
font-weight: 100;
8484
@media screen and (max-width: 768px) {
8585
font-size: 1rem;
8686
line-height: 1rem;

guides/testing-arquillian-junit5.adoc

+292
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
= Testing WildFly Applications with Arquillian and JUnit 5
2+
:summary: Testing applications with WildFly, Arquillian and JUnit 5
3+
:includedir: _includes
4+
include::{includedir}/_attributes.adoc[]
5+
// you can override any attributes eg to lengthen the
6+
// time to complete the guide
7+
:prerequisites-time: 15
8+
9+
In this guide you will learn how to setup your project for testing with Arquillian and JUnit 5. We will use the
10+
https://github.com/wildfly-extras/guides/tree/main/arquillian-junit5[arquillian-junt5] example project in this guide.
11+
12+
include::{includedir}/_prerequisites.adoc[]
13+
14+
== Add JUnit and Arquillian Dependencies
15+
16+
In order to use JUnit and Arquillian for your tests, you need to update the Maven `pom.xml`. The best practice is to
17+
import the Arquillian, JUnit 5 and WildFly Arquillian BOM's.
18+
19+
[source,xml]
20+
----
21+
<dependencyManagement>
22+
<dependencies>
23+
<dependency>
24+
<groupId>jakarta.platform</groupId>
25+
<artifactId>jakarta.jakartaee-bom</artifactId>
26+
<version>${version.jakarta.ee}</version>
27+
<scope>import</scope>
28+
<type>pom</type>
29+
</dependency>
30+
<dependency>
31+
<groupId>org.jboss.arquillian</groupId>
32+
<artifactId>arquillian-bom</artifactId>
33+
<version>${version.org.jboss.arquillian}</version>
34+
<type>pom</type>
35+
<scope>import</scope>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.wildfly.arquillian</groupId>
39+
<artifactId>wildfly-arquillian-bom</artifactId>
40+
<version>${version.org.wildfly.arquillian}</version>
41+
<type>pom</type>
42+
<scope>import</scope>
43+
</dependency>
44+
<dependency>
45+
<groupId>org.junit</groupId>
46+
<artifactId>junit-bom</artifactId>
47+
<version>${version.org.junit}</version>
48+
<type>pom</type>
49+
<scope>import</scope>
50+
</dependency>
51+
</dependencies>
52+
</dependencyManagement>
53+
----
54+
55+
You then need a minimum of the following dependencies.
56+
57+
[source,xml]
58+
----
59+
<dependencies>
60+
<dependency>
61+
<groupId>org.junit.jupiter</groupId>
62+
<artifactId>junit-jupiter</artifactId>
63+
<scope>test</scope>
64+
</dependency>
65+
<dependency>
66+
<groupId>org.jboss.arquillian.junit5</groupId>
67+
<artifactId>arquillian-junit5-container</artifactId>
68+
<scope>test</scope>
69+
</dependency>
70+
<dependency>
71+
<groupId>org.wildfly.arquillian</groupId>
72+
<artifactId>wildfly-arquillian-container-managed</artifactId>
73+
<scope>test</scope>
74+
</dependency>
75+
</dependencies>
76+
----
77+
78+
In this section we will work on writing a test for our application. We will assume here you already have experience
79+
writing Jakarta EE applications for WildFly. For the purpose of this test, we will use the
80+
https://docs.wildfly.org/wildfly-maven-plugin[wildfly-maven-plugin] to provision a server for testing.
81+
82+
== Configure POM for Provisioning
83+
84+
[source,xml]
85+
----
86+
<build>
87+
<plugins>
88+
<plugin>
89+
<groupId>org.wildfly.plugins</groupId>
90+
<artifactId>wildfly-maven-plugin</artifactId>
91+
<version>${version.wildfly-maven-plugin}</version>
92+
<configuration>
93+
<jboss-home>${jboss.home}</jboss-home>
94+
<provisioning-dir>${jboss.home}</provisioning-dir>
95+
<feature-packs>
96+
<feature-pack>
97+
<groupId>org.wildfly</groupId>
98+
<artifactId>wildfly-ee-galleon-pack</artifactId>
99+
</feature-pack>
100+
</feature-packs>
101+
<channels>
102+
<channel>
103+
<manifest>
104+
<groupId>org.wildfly.channels</groupId>
105+
<artifactId>wildfly-ee</artifactId>
106+
</manifest>
107+
</channel>
108+
</channels>
109+
<layers>
110+
<layer>ee-core-profile-server</layer>
111+
<layer>jpa</layer>
112+
<layer>h2-default-datasource</layer>
113+
<layer>transactions</layer>
114+
</layers>
115+
<galleon-options>
116+
<jboss-fork-embedded>true</jboss-fork-embedded>
117+
</galleon-options>
118+
</configuration>
119+
<executions>
120+
<execution>
121+
<id>provision-server</id>
122+
<goals>
123+
<goal>provision</goal>
124+
</goals>
125+
<phase>process-test-resources</phase>
126+
</execution>
127+
</executions>
128+
</plugin>
129+
</plugins>
130+
</build>
131+
----
132+
133+
The above configuration will provision a server based with Jakarta EE Core Profile specifications, Jakarta Persistence,
134+
Jakarta Transactions and the default H2 data source. The layers can be removed to provision a full WildFly server.
135+
136+
The provisioning is bound to the `process-test-resources` phase. This is the last phase before the `test` phase which
137+
is when our tests will be executed by default. We need a server before we can use Arquillian for our tests.
138+
139+
== Writing Tests
140+
141+
Now that our POM is configured, we can write a test for our application. The first step is to tell JUnit 5 we want
142+
to extend the functionality with Arquillian. The simplest approach is to annotate your test with `@ArquillainTest`. The
143+
other option is to annotate the test with `@ExtendWith(ArquillianExtension.class)`.
144+
145+
[source,java]
146+
----
147+
@ArquillianTest
148+
public class AddTaskResourceTest {
149+
}
150+
----
151+
152+
=== Client Test
153+
154+
Arquillian can run both in the container or as a client. For the first example we will run as a client. When running as
155+
a client the test runs outside the container. The simplest way to run as a client is to use the `@RunAsClient`
156+
annotation.
157+
158+
[source,java]
159+
----
160+
@ArquillianTest
161+
@RunAsClient
162+
public class AddTaskResourceTest {
163+
}
164+
----
165+
166+
The next thing Arquillian needs is a deployment. You can use Shrinkwrap to create a deployment.
167+
168+
NOTE: Shrinkwrap is a transitive dependency of Arquillian.
169+
170+
[source,java]
171+
----
172+
@ArquillianTest
173+
@RunAsClient
174+
public class AddTaskResourceTest {
175+
176+
@Deployment
177+
public static WebArchive createDeployment() {
178+
return ShrinkWrap.create(WebArchive.class)
179+
.addPackages(true, "org.wildfly.guide.testing")
180+
.addAsResource("META-INF/persistence.xml")
181+
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
182+
}
183+
}
184+
----
185+
186+
We can now add a test method using standard JUnit 5 testing strategies.
187+
188+
[source,java]
189+
----
190+
@ArquillianTest
191+
@RunAsClient
192+
public class AddTaskResourceTest {
193+
194+
@ArquillianResource
195+
private URI uri;
196+
197+
@Deployment
198+
public static WebArchive createDeployment() {
199+
return ShrinkWrap.create(WebArchive.class)
200+
.addPackages(true, "org.wildfly.guide.testing")
201+
.addAsResource("META-INF/persistence.xml")
202+
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
203+
}
204+
205+
@Test
206+
public void addTask() {
207+
final Task toAdd = new Task();
208+
toAdd.setSummary("This is a test task");
209+
toAdd.setDescription("This the test tasks description");
210+
try (
211+
Client client = ClientBuilder.newClient();
212+
Response createdResponse = client.target(UriBuilder.fromUri(uri).path("api/task/")).request()
213+
.post(Entity.json(toAdd))) {
214+
Assertions.assertEquals(Response.Status.CREATED, createdResponse.getStatusInfo(),
215+
() -> String.format("Invalid status: %s", createdResponse.readEntity(String.class)));
216+
// We should have the location
217+
try (Response response = client.target(createdResponse.getLocation()).request().get()) {
218+
Assertions.assertEquals(Response.Status.OK, response.getStatusInfo(),
219+
() -> String.format("Invalid status: %s - %s", createdResponse.readEntity(String.class),
220+
createdResponse.getLocation()));
221+
final Task resolvedTask = response.readEntity(Task.class);
222+
Assertions.assertNotNull(resolvedTask);
223+
Assertions.assertTrue(resolvedTask.getId() > 0,
224+
() -> String.format("Expected the task to have an ID greater than 0: %s", resolvedTask.getId()));
225+
}
226+
}
227+
}
228+
}
229+
----
230+
231+
NOTE: The `@ArquillianResource` can be used in inject various resources from Arquillian and WildFly Arquillian. In this
232+
example we inject a URI for the deployment.
233+
234+
=== In Container Test
235+
236+
In container tests have a similar structure to client based test. However, the test itself runs inside the container.
237+
This allows you to use CDI to inject beans into your test for example.
238+
239+
[source,java]
240+
----
241+
@ArquillianTest
242+
@RequestScoped
243+
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
244+
public class TaskRegistryTest {
245+
246+
@Inject
247+
private TaskRegistry taskRegistry;
248+
249+
@Deployment
250+
public static WebArchive createDeployment() {
251+
return ShrinkWrap.create(WebArchive.class)
252+
// Note for this test we don't use the REST endpoints so we don't need the REST resources
253+
.addClasses(TaskRegistry.class,
254+
Priority.class,
255+
Task.class,
256+
Producers.class,
257+
TaskListener.class)
258+
.addAsResource("META-INF/persistence.xml")
259+
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
260+
}
261+
262+
@Test
263+
@Order(1)
264+
public void addTask(final TestInfo testInfo) {
265+
final Task task = new Task();
266+
task.setAdded(Instant.now());
267+
task.setDescription("This is a test task from " + testInfo.getTestMethod()
268+
.map(Method::getName)
269+
.orElse("<unknown>"));
270+
task.setPriority(Priority.IMPORTANT);
271+
task.setSummary("Test summary");
272+
final var addedTask = taskRegistry.add(task);
273+
Assertions.assertEquals(task, addedTask);
274+
}
275+
}
276+
----
277+
278+
// Always keep a what's next? section to let the user know what could be achieved next
279+
== What's next?
280+
281+
Using JUnit 5 and Arquillian for testing offers several options for testing your application with WildFly. WildFly
282+
Arquillian includes some additional utilities not discussed in this guide such as the ability to configure server
283+
settings before your test executes. An advanced guide will dig deeper into the additional options for using Arquillian
284+
on WildFly.
285+
286+
// Always add this section last to link to any relevant content
287+
[[references]]
288+
== References
289+
290+
* https://arquillian.org[Arquillian]
291+
* https://docs.wildfly.org/wildfly-maven-plugin[WildFly Maven Plugin]
292+
* https://github.com/wildfly-extras/guides/tree/main/arquillian-junit5[Example Project]

0 commit comments

Comments
 (0)