Consider a Maven project with three modules Common
, ServiceA
, ServiceB
where both services depend on Common
and produce a war that is deployed as separate microservice. For each service I'd like to run an integration test, that checks the service exposes a healthcheck endpoint on /health
path.
@Test
open fun testHealthCheck() {
// implicitly asserts that response status is 200
perform("/health", method = RequestMethod.GET)
}
The only solution I could come up with is to duplicate this test into test packages of each service. However, that's not very DRY. I'd like this integration test to be defined in a single place (preferably in the Common
module) but to be run during the integration tests phase of each service.
How can I achieve that?
There are several ways to achive that. Both of that have pros and cons.
Maven can attach multiple artifacts to each modules (eg sources or tests, etc.). First step is to attach test classes of the shared module.
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<!-- ... -->
</build>
After this it's easy to use in an other project as a dependency:
<dependencies>
<dependency>
<groupId>io.github.zforgo.stackoverflow</groupId>
<artifactId>shared-tests</artifactId>
<version>0.1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
In the dependent project or module shared tests should unpack.
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<id>share-tests</id>
<phase>generate-test-sources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>io.github.zforgo.stackoverflow</groupId>
<artifactId>shared-tests</artifactId>
<version>0.1.0-SNAPSHOT</version>
<classifier>tests</classifier>
<outputDirectory>${project.build.testOutputDirectory}</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<!-- ... -->
</build>
NOTE : the ArtifactItem
ignores type
attribute so the classifier
attribute should used instead of type
. There is an issue in maven-dependency-plugin
issue tracking system. MDEP-732
During unit or integration test phase the unpacked classes will run.
[INFO] ---------------< io.github.zforgo.stackoverflow:project >---------------
[INFO] Building project 0.1.0-SNAPSHOT [3/3]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:3.1.2:unpack (share-tests) @ project ---
[INFO] Configured Artifact: io.github.zforgo.stackoverflow:shared-tests:tests:0.2.0-SNAPSHOT:jar
[INFO] Unpacking /work/source/stackoverflow/junit-test-sharing/multimodule-test-sharing/shared-tests/target/shared-tests-0.1.0-SNAPSHOT-tests.jar to /work/source/stackoverflow/junit-test-sharing/multimodule-test-sharing/project/target/test-classes with includes "" and excludes ""
[INFO]
[INFO] --- maven-surefire-plugin:3.0.0-M5:test (default-test) @ project ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running io.github.zforgo.stackoverflow.shared.SharedUnitTest
>>>> THIS IS A SHARED UNIT TEST <<<<
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.044 s - in io.github.zforgo.stackoverflow.shared.SharedUnitTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- maven-failsafe-plugin:3.0.0-M5:integration-test (default) @ project ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running io.github.zforgo.stackoverflow.shared.SharedIntegrationTestIT
>>>> THIS IS A SHARED INTEGRATION TEST <<<<
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.005 s - in io.github.zforgo.stackoverflow.shared.SharedIntegrationTestIT
Pros | Cons |
---|---|
Both unit and integration tests shared in one step. | Needs a workaround cause of MDEP-732 |
Shared tests will be packed into dependent artifact. Prevent changes. | Class duplication makes dependent test-jar bigger unnecessarily. |
Inclusion and exclusion supported during unpack. |
<dependenciesToScan>
attribute (recommended)First of all I'd like to say thanks to @khmarbaise for suggestion.
Fortunately both maven-surefire-plugin
and maven-failsafe-plugin
has <dependenciesToScan>
configuration attribute. All those listed dependencies will be scanned for test classes to include and run. NOTE Listed artifacts must be <dependency>
elements in the dependent project or module.
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.github.zforgo.stackoverflow</groupId>
<artifactId>shared-tests-aggregator</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>project</artifactId>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>shared-tests</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<dependenciesToScan>
<dependency>${project.groupId}:shared-tests:test-jar</dependency>
</dependenciesToScan>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M5</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<dependenciesToScan>
<dependency>${project.groupId}:shared-tests:test-jar</dependency>
</dependenciesToScan>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
NOTE : maven-failsafe-plugin:integration-test
goal will report false error messages to console if the same package is missing in the dependent project.
[INFO]
[INFO] --- maven-failsafe-plugin:3.0.0-M5:integration-test (default) @ project ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[ERROR] WARNING: package io.github.zforgo.stackoverflow.shared not in project
[INFO] Running io.github.zforgo.stackoverflow.shared.SharedIntegrationTestIT
>>>> THIS IS A SHARED INTEGRATION TEST <<<<
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.034 s - in io.github.zforgo.stackoverflow.shared.SharedIntegrationTestIT
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
Pros | Cons |
---|---|
Easy to separate unit- and integration test sharing | Configuration must be duplicated when unit- and integration tests are shared |
Shared tests wont copied, no class duplication | Delusive [ERROR] messages in logs but build is success. |
Responsible plugins will handle dependent test classes | Possible configuration changes time to time, version to version. Always read the documentation |
build-helper-maven-plugin
This MojoHaus plugin allows to use multiple source or test-source directories in one module or project.
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.github.zforgo.stackoverflow</groupId>
<artifactId>shared-tests</artifactId>
<version>0.1.0-SHAPSHOT</version>
</parent>
<artifactId>project</artifactId>
<dependencies>
<dependency>
<groupId>io.github.zforgo.stackoverflow</groupId>
<artifactId>shared-test</artifactId>
<version>0.1.0-SHAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>${project.parent.basedir}/shared-test/src/test/java/com/example/demo/shared</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Pros | Cons |
---|---|
Works only with local folders. External artifacts not supported. | |
Folders are hardcoded. Maintenance issues. |
In short there are more possibilities to share tests between projects and modules but it's your turn to chose the best one.
What about creating a new Maven module specifically for integration testing? This module can then depend on both ServiceA
and ServiceB
. Your tests can then be run as part of the integration tests phase of this new module.
You may want to use the Maven failsafe plugin for integration tests. This allows integration tests to run from a separate goal. The reason for doing that would be for Continuous Integration tools such as Jenkins, where you would want unit tests to run, but not integration tests because, for example, they depend on an external web service running. If that service was not running, your CI build would fail.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.