At work I'm splitting up an existing Quarkus application into several modules:
A
, B
and C
containing controllers/API endpointsshared
module for shared code and database accessdeployment
module that bundles all modules together for deploymentThe idea is that I can combine different versions of A
, B
and C
in production (perhaps I am not ready to deploy my changes to A
to production, even though I want to deploy the changes in B
now).
Strictly speaking, the quarkus-maven-plugin
is only required for the deployment
module because that is the only module that I will want to run as a Quarkus application.
However, because each of the application modules is responsible for a set of endpoints, it seems logical to put the integration tests (@QuarkusTest
s) for those in the application modules themselves. However, this will require the quarkus-maven-plugin
for each of the modules, only for the purpose of being able to run the integration tests.
Are there any adverse effects of doing this?
An alternative I'm considering is to put the integration tests for each application module in seperate modules (A-tests
, B-tests
and C-tests
) and include the quarkus-maven-plugin
in those. Is that better?
It can be solved but it is not straight forward.
The following tasks have to be done
At first, I have to clarify this
the
quarkus-maven-plugin
is only required for thedeployment
module because that is the only module that I will want to run as a Quarkus application.
One of the most important concept of Quarkus to favor build time work over runtime. That's why quarkus-maven-plugin
does much more than just build deployable artifact. So, this plugin is always required by each module wheter that module is deployable or not.
Let's say there are three modules (four pom.xml
files)
*-parent - An aggregator which contains common settings, plugin templates, dependencies used by all submodules, etc.
*-module-[a-z] - application modules contains business logic, endpoints, shared entities. There modules are not deployable artifacts.
*-deployment - Deployable Quarkus application which can use other modules as dependencies, can contain other business logic and / or endpoints, entities, whatever.
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.zforgo</groupId>
<artifactId>so-78088326-quarkus-multi-module-testing-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<compiler-plugin.version>3.12.1</compiler-plugin.version>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.8.1</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.2.5</surefire-plugin.version>
</properties>
<modules>
<module>so-78088326-module-a</module>
<module>so-78088326-module-b</module>
<module>so-78088326-deployment</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<id>generate-code</id>
<goals>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
<execution>
<id>build-deployable-app</id>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<inherited>true</inherited>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner
</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
There are two remarkable things in the <pluginManagement>
section.
maven-jar-plugin
configured to create another artifact which contains test classes (more precisely all classes and resources under test folder). This configuration allows us to share even integration tests between other modules.quarkus-maven-plugin
configured a little differently than as usual. The build
goal moved under another <execution>
section and got an <id>
tag. From now, the build
(which creates a deployable artifact) goal can be eliminated when it is needed,<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.github.zforgo</groupId>
<artifactId>so-78088326-quarkus-multi-module-testing-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
</parent>
<artifactId>so-78088326-module-a</artifactId>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<executions>
<execution>
<id>build-deployable-app</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
A non-deployable Quarkus module can be referenced as a dependency, it can be started during the test phase but it cannot be started like a standalone Quarkus application. By binding the build-deployable-app
execution to the none
lifecycle phase, quarkus:build
goal will be disabled.
Don't forget to make these modules discoverable to the main (deployable) module's CDI bean discovery mechanism by configuring jandex-maven-plugin
or by adding a beans.xml
to every non-deployable submodules.
In the Quarkus ecosystem the deployment module means totally different. Every Quarkus extension has a deployment
submodule that handles build time processing and so on.
In this case a deployment module has to be build as a deployable Quarkus application using other submodules and probably some own code (e.g. other Rest endpoint)
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.github.zforgo</groupId>
<artifactId>so-78088326-quarkus-multi-module-testing-parent</artifactId>
<version>0.1.0-SNAPSHOT</version>
</parent>
<artifactId>so-78088326-deployment</artifactId>
<properties>
<skipITs>false</skipITs>
</properties>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
</plugin>
<!-- ... -->
</plugins>
</build>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>so-78088326-module-a</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>so-78088326-module-b</artifactId>
<version>${project.version}</version>
</dependency>
<!-- ... -->
</dependencies>
</project>
Here, the build
goal of quarkus-maven-plugin
enabled and bound to package
lifecycle phase by default.
Let's say every module has own tests. Every test class that annotated with @QuarkusTest
should run during the submodule's test
phase, but the @QuarkusIntegrationTest
s should be shared and run during integration-test
phase of deployment module.
In the aggregator module maven-jar-plugin
has already configured to create test jar artifact. These artifacts are available like:
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>so-78088326-module-a</artifactId>
<version>${project.version}</version>
<scope>test</scope>
<type>test-jar</type>
</dependency>
In the aggreagator module the integration tests disabled by default by using <skipITs>true</skipITs>
property. Well, disabling the skipping of integration test will enable them, won't it? In the deployment module skipITs
property has to be set to false
In order to run integration tests from external artifacts the maven-failsafe-plugin
has to be configured properly. The dependenciesToScan
parameter allows to specify and execute integration tests from dependencies.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration combine.children="append">
<dependenciesToScan>
<dependency>${project.groupId}:so-78088326-module-a:test-jar</dependency>
<dependency>${project.groupId}:so-78088326-module-b:test-jar</dependency>
</dependenciesToScan>
</configuration>
</plugin>
Important! All those included dependencies must already be defined in <dependencies>
For further options see the official documentation.