Overview and Online Documentation
See http://maven.apache.org/users/index.html.
Maven is a software tool for Java project management and build automation, similar in functionality to the Apache Ant tool coupled to a dependency manager such as Ivy, but Maven is based on different concepts.
Maven uses a construct known as a Project Object Model (POM) to describe the software project being built, its dependencies on other external modules and components, and the build order. It comes with predefined targets for performing certain well defined tasks such as compilation of code and its packaging.
Maven is designed to be network-ready. It dynamically downloads libraries and plugins from one or more repositories. A local cache of downloaded artifacts acts as the primary means of synchronizing the requirements and outputs of projects on a local system.
Online Documentation
http://www.sonatype.com/books/maven-book/reference/
http://maven.apache.org/guides/
http://maven.apache.org/guides/introduction/
http://maven.apache.org/ref/2.1.0/maven-settings/settings.html
Nuxeo Documentation
In the knowledge base: How to debug test run with Maven.
Installing Maven
What is Maven?
Quoting the Wikipedia entry for Maven:
Maven is a software tool for Java programming language project management and automated software build. It is similar in functionality to the Apache Ant tool, but has a simpler build configuration model, based on an XML format. Maven is hosted by the Apache Software Foundation, where it was formerly part of the Jakarta Project.
Maven uses a construct known as a Project Object Model (POM) to describe the software project being built, its dependencies on other external modules and components, and the build order. It comes with predefined targets for performing certain well defined tasks such as compilation of code and its packaging.
A key feature of Maven is that it is network-ready. The core engine can dynamically download plugins from a repository, the same repository that provides access to many versions of different Open Source Java projects, from Apache and other organizations and developers. This repository and its reorganized successor the Maven 2 repository are the de facto distribution mechanism for Java applications. Maven provides built in support not just for retrieving files from this repository, but to upload artifacts at the end of the build. A local cache of downloaded artifacts acts as the primary means of synchronizing the output of projects on a local system.
Nuxeo is fully "Maven managed".
Nuxeo holds a Maven repository here: http://maven.nuxeo.org/.
Installing Maven
You should install Maven on your development box by downloading the latest archive from http://maven.apache.org/download.html and then extract the archive into /opt
(for instance).
As usual, you have to put the mvn executable into the path of your environment, include the bin/
sub-directory in your PATH
by adding in your .bashrc
(or .profile
, .zprofile
, ...) something like:
export M2_HOME=/opt/apache-maven-3.3.3/
export PATH=/opt/apache-maven-3.3.3/bin:$PATH
In a new shell you can then test:
$ mvn --version
Apache Maven 3.3.3 (...)
Maven home: /opt/apache-maven-3.3.3
Java version: 1.8.0_51, vendor: Oracle Corporation
Configure Repositories
Nuxeo uses Sonatype Nexus OSS for storing its artifacts at https://maven.nuxeo.org/.
You will find there a lot of "group", "hosted" and "proxy" repositories:
- .../groups/public/ and .../groups/public-snapshot/ . Those are the preferred entry points. They are groups aggregating all other repositories.
- .../repositories/public-releases/ and .../repositories/public-snapshots/ Here are stored all Nuxeo published artifacts. Those are internally hosted Nuxeo repositories.
- .../groups/thirdparty-releases/ and .../groups/thirdparty-snapshots/ Those groups deliver everything except Nuxeo artifacts (i.e. thirdparty-releases = public - public-releases).
- .../repositories/vendor-releases/ and .../repositories/vendor-snapshots/ Here are stored all third-party artifacts which were not available on Internet as Maven artifacts (because their editor does not manage their own public Maven repository, neither publish in available ones; or because Nuxeo has applied some patches on them).
- .../repositories/hotfix-releases-group/ and .../repositories/hotfix-snapshots/ Here are stored all Nuxeo published Hotfix artifacts. Those are internally hosted Nuxeo repositories. The access is restricted to Nuxeo customers.
- Various proxy repositories from which Nuxeo retrieve some artifacts. These are public repositories from Apache, Atlassian, Codehaus, Google, ibiblio, JBoss, Maven Central (of course), Sonatype...
There are three solutions for enabling your Maven build to use Nuxeo repositories:
- add
public
andpublic-snapshot
repositories in your POM:
<repositories>
<repository>
<id>public</id>
<url>http://maven.nuxeo.org/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>public-snapshot</id>
<url>http://maven.nuxeo.org/nexus/content/groups/public-snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<updatePolicy>always</updatePolicy>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
- add
public
andpublic-snapshot
repositories in your$M2_REPO/settings.xml
: The same sentence must be put inside a profile.
<?xml version="1.0"?>
<settings>
<profiles>
<profile>
<id>Nuxeo</id>
<repositories>
<repository>
<id>public</id>
<url>http://maven.nuxeo.org/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>public-snapshot</id>
<url>http://maven.nuxeo.org/nexus/content/groups/public-snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<updatePolicy>always</updatePolicy>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>Nuxeo</activeProfile>
</activeProfiles>
</settings>
- define mirrors in your
$M2_REPO/settings.xml
: If your company is hosting its own Maven repository manager with proxies to Nuxeo repositories, you can define that mirroring in your Maven settings.
<?xml version="1.0"?>
<settings>
<!-- Bypass POM information to avoid remote repositories and use internal ones instead -->
<mirrors>
<mirror>
<id>public-releases-mirror</id>
<name>public releases mirror</name>
<url>http://your.company.com/.../proxy-to-nuxeo-release</url>
<mirrorOf>public</mirrorOf>
</mirror>
<mirror>
<id>public-snapshots-mirror</id>
<name>public snapshots mirror</name>
<url>http://your.company.com/.../proxy-to-nuxeo-snapshot</url>
<mirrorOf>public-snapshot</mirrorOf>
</mirror>
</mirrors>
</settings>
If you are behind an HTTP proxy, see http://maven.apache.org/settings.html#Proxies.
Configure Hotfix Repositories
Nuxeo customers have access to two additional repositories where the "hotfix" artifacts are deployed: hotfix-releases-group
and hotfix-snapshots
.
Contact the Nuxeo support to get an account.
Add the repositories in your POM:
<repositories>
<!-- Hotfix Repositories For Nuxeo Customers Only -->
<repository>
<id>hotfix-releases</id>
<url>https://maven.nuxeo.org/nexus/content/groups/hotfix-releases-group/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>hotfix-snapshots</id>
<url>https://maven.nuxeo.org/nexus/content/repositories/hotfix-snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<updatePolicy>always</updatePolicy>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
Set your credentials in your $M2_REPO/settings.xml
:
<!-- In case of redirection error, for instance, from nuxeo.org to nuxeo-us instead of nuxeo-eu -->
<!--
<mirrors>
<mirror>
<id>hotfix-releases-eu</id>
<name>hotfix releases EU</name>
<url>https://maven-eu.nuxeo.org/nexus/content/groups/hotfix-releases-group</url>
<mirrorOf>hotfix-releases</mirrorOf>
</mirror>
<mirror>
<id>hotfix-snapshots-eu</id>
<name>hotfix snapshots EU</name>
<url>https://maven-eu.nuxeo.org/nexus/content/repositories/hotfix-snapshots</url>
<mirrorOf>hotfix-snapshots</mirrorOf>
</mirror>
</mirrors>
-->
<servers>
<server>
<id>hotfix-releases</id>
<username>****</username>
<password>****</password>
</server>
<server>
<id>hotfix-snapshots</id>
<username>****</username>
<password>****</password>
</server>
</servers>
Configuring Plugin Repositories
Maven plugins are considered as special artifacts: their repositories must also be configured. Follow exactly the same instructions as above replacing repositories/repository
sections with pluginRepositories/pluginRepository
.
Configure Eclipse with Maven
The maven-eclipse-plugin provides a goal (eclipse:configure-workspace
) for automatically configuring Eclipse with Maven but it's easy to manually configure: in Eclipse, go to Preferences/Java/Build Path/Classpath Variables
, click New
, name M2_REPO
and browse to your local Maven repository (usually ~/.m2/repository
).
Maven usage for LTS 2023
Nuxeo Platform LTS 2023 artifacts are private. Consequently, you'll need to create a support ticket to request access to the Nuxeo Central Repository, https://packages.nuxeo.com/.
Once your Okta account is assigned the “Sonatype Nexus“ application, go to https://auth.nuxeo.com and click on the application.
You should then connect to packages using the “single sign-on” feature and then:
- Click on its username,
- Click on User Token menu,
- Push the button Access user token to generate a token to download the artifacts from Maven.
You'll be able to get your credentials for the XML file:
Use the following in your Maven settings.xml:
<server>
<id>${server}</id>
<username><MY_NEXUS_USERNAME></username>
<password><MY_NEXUS_PASSWORD></password>
</server>
Use the following for a base64 representation of "user:password":
<MY_BASE_64_REPRESENTATION_CREDENTIALS>
Finally, update your POM file with the credentials you've just generated.
Generate a New Project with the Nuxeo-Archetype-Start Archetype
The goal of the nuxeo-archetype-start template is to setup a development environment to work on a Nuxeo Platform plugin.
The default code provides: a Maven layout for sources, tests and dependencies, a Ant target for deployment. It also customizes the web application a little bit.
To create a project named my-project in the com.company.sandbox.myproject package:
mvn org.apache.maven.plugins:maven-archetype-plugin:1.0-alpha-7:create \
-DartifactId=my-project \
-DgroupId=com.company.sandbox.myproject \
-DarchetypeArtifactId=nuxeo-archetype-start \
-DarchetypeGroupId=org.nuxeo.archetypes \
-DarchetypeVersion=5.1.6 \
-DremoteRepositories=http://maven.nuxeo.org/nuxeo-release
You can see that you need to supply six arguments:
artifactId
: the name of your project, usually with '-' to separate the words if there are many.groupId
: the domain name of your project. Usually it is the package parent name of your classes, you should use '.' to separate the words ('-' is not supported here).archetypeArtifactId
: the Maven archetype artifact id. To generate a new project, Nuxeo provides you with nuxeo-archetype-startarchetypeGroupId
: unique for all Nuxeo Maven archetypes : org.nuxeo.archetypesarchetypeVersion
: the version of the archetype which is equivalent to the version of Nuxeo Platform without the _GA_ or _RC_ part. (5.1.6, 5.1.5 ...).remoteRepositories
: the repository location to download the archetype.
Decrease Build Time
No Clean
Maven is able to decrease build time but it relies on target content for this. If you don't "clean" the target directory, only out of date modules are rebuilt. Issue is not cleaning the target directory may lead to strange results because of deprecated uncleaned resources.
The incremental-build-plugin provides a solution for this: checking the target content during the Maven validation phase, it deletes the target directory when it's needed.
This plugin is automatically activated when using Nuxeo corporate POM (org.nuxeo:nuxeo-ecm
since version 5.4.0-SNAPSHOT).
You don't need to "clean" anymore while building sources.
Note that when using for instance mvn install
, even if a module is not rebuilt, its target content is installed; which is a good thing for SNAPSHOT consistency but leads to a consequent build time even if there's nothing to recompile.
Multi-Thread
Maven 3 enables multi-threaded builds. Of course, it requires the activated plugins being thread-safe, as well as the Unit Tests code. See below for -T
option details.
No SNAPSHOT Updates and Offline Mode
See related -o
and -nsu
options below.
Skip Tests
Skip all tests execution with -DskipTests
(Unit Tests and Integration Tests).
Skip only the Integration Tests execution with -DskipITs
.
Skip only the Unit Tests execution with -Dskip.surefire.tests=true
.
-Dmaven.test.skip=true
which also skips the tests compilation.
In the Maven Surefire Test Framework:
- Unit Tests are managed by the
maven-surefire-plugin
during thetest
phase. - Integration Tests are managed by the
maven-failsafe-plugin
during theintegration-test
andverify
phases. - Test classes selection is based on the filename patterns and the plugin configuration: see Surefire Inclusions and Exclusions of Tests and Failsafe Inclusions and Exclusions of Tests.
In the Nuxeo Test Framework:
- There is no difference about the Unit Tests except that they can act like Integration Tests: "unit testing" multiple modules at once, at a higher level than usual per-module Unit Tests.
That advanced behavior may disturb analysis tools (like Cobertura, Jacoco, SonarQube...) and require a specific configuration to get relevant coverage reports (see
org.nuxeo:nuxeo-ecm
POM). - Integration Tests designate Functional and Performance Tests.
- Selenium, FunkLoad and other custom Integration Tests are managed by the
ant-assembly-maven-plugin
which mimicsmaven-failsafe-plugin
behaviors, honoring its main properties and output format. - WebDriver Integration Tests are managed by the
maven-failsafe-plugin
; theant-assembly-maven-plugin
acts only duringpre-integration-test
andpost-integration-test
phases for the environment set up and tear down.
Basic Maven Options
Non Recursive
-N,--non-recursive Do not recurse into sub-projects
Offline Mode
-o,--offline Work offline
Activate/Deactivate Profiles
-P,--activate-profiles <arg> Comma-delimited list of profiles to activate
This can also be used to deactivate a profile by preceding the profile to deactivate with a - (dash).
Force Artifacts Update
-U,--update-snapshots Forces a check for updated releases and snapshots on remote repositories
Nuxeo default snapshots update policy is "always", so you need this option only if you changed this policy.
No SNAPSHOT updates
-nsu,--no-snapshot-updates Suppress SNAPSHOT updates
Advanced Maven Options
Projects list (-pl)
-pl,--projects <arg> Build specified reactor projects instead of all projects
For instance, the following will build only modules A and B even if there are others in the modules list of your POM:
mvn install -pl A,B
Useful for building a restricted modules list.
Also Make (Upstream Dependencies)
-am,--also-make If project list is specified, also build projects required by the list
For instance, the following will build all modules required by A and B, then A and B:
mvn install -pl A,B -am
Useful for building only modules that may impact the restricted modules list you are currently working on.
Also Make (Downstream) Dependencies
-amd,--also-make-dependents If project list is specified, also build projects that depend on projects on the list
For instance, the following will build A and B, then all modules depending on A or B:
mvn install -pl A,B -amd
Useful to check collateral impacts of changes you've done on a restricted modules list.
Resume From
-rf,--resume-from <arg> Resume reactor from specified project
Maven will skip modules until it reaches the named module. Useful when your build failed for some reason you've fixed and you don't want to replay useless previous builds.
Multi-Threading
-T,--threads <arg> Thread count, for instance 2.0C where C is core multiplied
Errors and Debug
-e,--errors Produce execution error messages
-X,--debug Produce execution debug output
There are two possible errors raised by the Maven plugins: MojoExecutionException
and MojoFailureException
. A MojoExecutionException
is a fatal exception, stopping the build; whereas a MojoFailureException
is more like a warning for which you can customize the build result with the following options. Those options are common to all plugins and must be preferably used to plugins' specific options such as -Dmaven.test.haltafterfailure=true
or -Dmaven.test.failure.ignore=true
.
-fae,--fail-at-end Only fail the build afterwards; allow all non-impacted builds to continue
Regarding the tests, with -fae
option, Maven will remember the failing tests and skip their downstream (dependent) modules but only report the failures after the whole build. This is more or less equivalent to the maven.test.haltafterfailure
Surefire option.
-ff,--fail-fast Stop at first failure in reactorized builds
-fn,--fail-never NEVER fail the build, regardless of project result
Tips and Workarounds
Do not use activeByDefault
- Use Activation by the Absence of a Property
The activeByDefault
profile configuration parameter should never be used, instead rely on the activation by the absence of a property as a workaround.
No
<profile>
<id>defaultProfile</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
mvn help:active-profiles
shows that the profile defaultProfile
is implicitly deactivated if any other profile is active (which is more than frequent), making the behavior variable, depending on the environment and the POM content.
mvn help:active-profiles -PanotherProfile
will implicitly deactivate the "(expected to be) active by default profile" defaultProfile
!
Yes
<profile>
<id>defaultProfile</id>
<activation>
<property>
<name>!skipDefaultProfile</name>
</property>
</activation>
</profile>
mvn help:active-profiles
shows that the profile is always activated unless being explicitly deactivated.
mvn help:active-profiles -P-defaultProfile
or mvn help:active-profiles -DskipDefaultProfile
both explicitly deactivate the skipDefaultProfile
as intuitively expected.
Explanations
The activeByDefault
profile configuration parameter should never be used because it is counter-intuitive and actually useless: it activates only if no other profile is activate (explicitly, through Maven settings, based on configuration...). Finally, such a profile is never activated when we want.
The documentation states:
This profile will automatically be active for all builds unless another profile in the same POM is activated using one of the previously described methods (explicitly, through Maven settings, based on environment variables, OS settings, present or missing files).
According to MNG-4917: Profile not active even though it has activeByDefault set to true, this issue won't be fixed as it is not a bug but only a useless counter-intuitive feature.
Fix maven-eclipse-plugin
Warning about Workspace's vm (Mac OS X Only)
Because of indefinitely unresolved issue MECLIPSE-668, Mac OS X users get the following warning message when running mvn eclipse:eclipse
command:
[WARNING] Workspace defines a VM that does not contain a valid jre/lib/rt.jar: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
Apply that workaround:
cd /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
sudo mkdir -p jre/lib
sudo ln -s /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/classes.jar jre/lib/rt.jar
Common settings.xml
File for Nuxeo Core Developers
<settings>
<!--
<mirrors>
<mirror>
<id>public-releases-mirror</id>
<name>public releases mirror</name>
<url>http://mavenin.nuxeo.com/nexus/content/groups/public</url>
<mirrorOf>public</mirrorOf>
</mirror>
<mirror>
<id>public-snapshots-mirror</id>
<name>public snapshots mirror</name>
<url>http://mavenin.nuxeo.com/nexus/content/groups/public-snapshot</url>
<mirrorOf>public-snapshot</mirrorOf>
</mirror>
</mirrors>
-->
<servers>
<!-- See http://maven.apache.org/guides/mini/guide-encryption.html for password encryption -->
<server>
<id>nightly-staging</id>
<username>****</username>
<password>****</password>
</server>
<server>
<id>public-releases</id>
<username>****</username>
<password>****</password>
</server>
<server>
<!-- private releases -->
<id>releases</id>
<username>****</username>
<password>****</password>
</server>
<server>
<id>vendor-releases</id>
<username>****</username>
<password>****</password>
</server>
<server>
<id>public-snapshots</id>
<username>****</username>
<password>****</password>
</server>
<server>
<!-- internal snapshots -->
<id>daily-snapshots</id>
<username>****</username>
<password>****</password>
</server>
<server>
<!-- private snapshots -->
<id>snapshots</id>
<username>****</username>
<password>****</password>
</server>
<server>
<id>vendor-snapshots</id>
<username>****</username>
<password>****</password>
</server>
<server>
<id>nuxeo-studio</id>
<username>****</username>
<password>****</password>
</server>
<server>
<id>maven-website</id>
<username>mavenweb</username>
</server>
</servers>
<profiles>
<profile>
<id>NXP</id>
<repositories>
<repository>
<id>public</id>
<url>http://maven.nuxeo.org/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>public-snapshot</id>
<url>http://maven.nuxeo.org/nexus/content/groups/public-snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<updatePolicy>always</updatePolicy>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<properties>
<connect.password>****</connect.password>
</properties>
</profile>
<profile>
<id>qa</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<repositories>
<repository>
<id>internal-releases</id>
<url>http://mavenin.nuxeo.com/nexus/content/groups/internal-releases</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>internal-snapshots</id>
<url>http://mavenin.nuxeo.com/nexus/content/groups/internal-snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories>
<properties>
<connect.password>****</connect.password>
</properties>
</profile>
<profile>
<!-- No SNAPSHOT Updates (useless Since Maven 3.1.1 which provides a -nsu option) -->
<id>qansu</id>
<repositories>
<repository>
<id>internal-snapshots</id>
<url>http://mavenin.nuxeo.com/nexus/content/groups/internal-snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
</repository>
<repository>
<id>public-snapshot</id>
<url>http://maven.nuxeo.org/public-snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
</repository>
</repositories>
</profile>
<profile>
<id>qapriv</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<repositories>
<repository>
<id>private-releases</id>
<url>https://mavenpriv.nuxeo.com/nexus/content/groups/private-releases</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>private-snapshots</id>
<url>https://mavenpriv.nuxeo.com/nexus/content/groups/private-snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories>
</profile>
<profile>
<id>release</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<keystore.path>****</keystore.path>
<keystore.password>****</keystore.password>
<keystore.alias>****</keystore.alias>
<connect.password>****</connect.password>
</properties>
</profile>
(...)
</profiles>
<activeProfiles>
<activeProfile>qa</activeProfile>
</activeProfiles>
<pluginGroups>
<pluginGroup>org.nuxeo.build</pluginGroup>
<pluginGroup>org.jvnet.hudson.tools</pluginGroup>
<pluginGroup>org.jenkins-ci.tools</pluginGroup>
<pluginGroup>com.versioneye</pluginGroup>
</pluginGroups>
</settings>
Build and Use a Test-Jar with Maven
If you want to expose your test class to be reused in other test classes of projects you can add the following code at the end of your pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
If you don't want to include the manifest file of your bundle to use the one defined in your test resources folder, you can add the following code in the execution
tag of your pom:
<configuration>
<archive>
<manifestFile>src/test/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
The aim is to not build a test jar containing the manifest of the main bundle, because the manifest will probably defined a "Nuxeo-Component" item pointing to a service xml file that you don't embedded in the test jar. This will cause the following error when you will deploy your test bundle with maven:
Unknown component 'OSGI-INF/your-service.xml' referenced by bundle 'your.bundle.id'
Then, to use this test package in your code you must define a dependency like this:
<dependency>
<groupId>the.group.id</groupId>
<artifactId>the-artifact-name</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>