Sharing Test code in Maven - maven-2

How can you depend on test code from another module in Maven?
Example, I have 2 modules:
Base
Main
I would like a test case in Main to extend a base test class in Base. Is this possible?
Update: Found an acceptable answer, which involves creating a test jar.

I recommend using type instead of classifier (see also: classifier). It tells Maven a bit more explicitly what you are doing (and I've found that m2eclipse and q4e both like it better).
<dependency>
<groupId>com.myco.app</groupId>
<artifactId>foo</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>

Thanks for the base module suggestion. However, I'd rather not create a new module for just this purpose.
Found an acceptable answer in the Surefire Maven documentation and a blog. See also "How to create a jar containing test classes".
This creates jar file of code from src/test/java using the jar plugin so that modules with tests can share code.
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
In order to use the attached test JAR that was created above you simply specify a dependency on the main artifact with a specified classifier of tests:
<project>
...
<dependencies>
<dependency>
<groupId>com.myco.app</groupId>
<artifactId>foo</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
...
</project>

We solved this by making a maven project with test code as the src/main/java and adding the following dependency to projects:
<dependency>
<groupId>foo</groupId>
<artifactId>test-base</artifactId>
<version>1</version>
<scope>test</scope>
</dependency>

Worked for me for 1 project, but I didn't for another after doing exactly the same steps.
So I debugged:
After mvn clean install I checked /target directory: .jar was there so thats good
Ran mvn dependency:tree on a project which should use those test classes. Noticed that generated jar file with test classes is marked as dependency, so thats good.
Conclusion could be only one - I restarted my Intellj. At first class import was still not visible, but after a minute it started to see it!
Note: I only restarted Intellj, no caches removal etc

Yep ... just include the Base module as a dependency in Main. If you're only inheriting test code, then you can use the scope tag to make sure Maven doesn't include the code in your artifact when deployed. Something like this should work:
<dependency>
<groupId>BaseGroup</groupId>
<artifactId>Base</artifactId>
<version>0.1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>

Related

New at Maven: Using the shade plugin and 3rd party jars

This should be pretty simple, but I can't the around to it. I need to create an uberjar using 3rd party jars. I've already followed these instructions: Including a non-Mavenized dependency so it works with maven-shade-plugin and added them to the local repository. But now what? Every Maven tutorial/example is kinda shady (pun intended) and I just don't know how to edit the .pom file properly in order to make it work.
Besides, I'm confused about the shade "plugin" overall. I mean, I followed the basic Maven tutorials and it went all fine and dandy. But when I look into the shade plugin page, I can't find it to download, except for the source code. I mean, isn't it a plugin? Shouldn't I download the binaries and install it into Maven somehow?
Sorry about the extreme noobish question but, needless to say, I know squat about Maven.
To create your shaded (uber) jar, you just need to declare the shade plugin in your pom.xml.
With regards to installation of the shade plugin, simply declaring it in the plugins section of your pom.xml is all you need do. Maven plugins are not installed manually, but are automatically downloaded by Maven (if not already downloaded; just like dependencies), stored in your local repository, and used whenever a project needs them.
As to using it, much like other plugins, declare it in your pom.xml by adding a <plugin> element with your configuration needs. This plugin does nothing automatically (some do, some don't) - you have to specify which "goal" to execute (think "method of a class"), and in which "phase" (think "step" of the build process). Unless you have strange needs, specify the "shade" goal in the "package" phase (see below).
For more configuration possibilities, see the shade usage page, and their examples (especially selecting contents for uber jar). Here is a simple example which, when you run mvn package, replaces your original jar in the target/ directory with the uber jar. It only includes the runtime dependencies, not the ones used at test time (notice the <scope> element of the junit dependency, which is not included in the uber jar).
<project>
<groupId>com.sample</groupId>
<artifactId>test</artifactId>
<version>1.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.sample</groupId>
<artifactId>test-core</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
If you have already downloaded the binaries and installed them into your local Maven repository all that remains is to declare them as dependencies in the POM. If the shade plugin is also declared in the POM a simple "mvn install" should generate a standalone JAR in the target directory.

Maven plugin dependencies are ignored

I created this profile for deploying artifacts on the server via SCP. I know Ant's scp task is optional, therefore I've added the dependencies.
<profiles>
<profile>
<id>remote-deploy</id>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>scp</id>
<phase>install</phase>
<configuration>
<tasks>
<scp .../>
<sshexec .../>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-jsch</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.42</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</profile>
</profiles>
However, when I run the profile, I end up with
An Ant BuildException has occured:
Problem: failed to create task or type
scp Cause: the class
org.apache.tools.ant.taskdefs.optional.ssh.Scp
was not found.
This looks like one of Ant's optional components. Action: Check
that the appropriate optional JAR
exists in
-ANT_HOME\lib
-the IDE Ant configuration dialogs
Do not panic, this is a common
problem. The commonest cause is a
missing JAR.
This is not a bug; it is a
configuration problem
Is it possible maven wasn't able to download those dependencies or it just ignores them?
The problem was Maven (2.2.1) didn't download the dependencies. I've found out after I upgraded Maven to version 3. For some reason,the new version downloaded the plugin dependencies and it miraculously started to work.
I have a suspicion the problem was in old version Maven's settings - pluginRepository wasn't configured.
It is likely that maven has downloaded the jars but it is not in ant's classpath. If the objective is to deploy the artifacts using maven, you should probably use Maven Deploy Plugin. What you are doing seems to be a roundabout way.
There is a maven-antrun-plugin bug entry, that could explain why this is happening in Maven-2, they also describe workarounds
In multi-module builds, if there are multiple poms configuring the maven-antrun-plugin, the first(?) seems to win, so that the ones later in the build chain reuse the antrun config from earlier poms, thus missing out on stuff that is different ...
In my problem case, I opted to use Maven-3, where the issue seems to be fixed, instead of workarounds with Maven-2. This had the additional advantage of the build to also speed up - now taking 6min instead of the 10min before.
However, if Maven-3 is not possible for you, I'd try the workarounds...

Maven2: dependency set to compile not added to war

I have a multi module project consisting of several jar modules and a war module. When I do mvn package, the war is created but one dependency (javax.mail) is not included in the lib folder of the war.
The dependency is set to compile is the main pom. The war is not dependent from the mail.jar but a module.jar is.
When I do mvn dependency:tree, the three looks fine to me. Running in debug does not show me anything wrong either.
Anyone has an idea?
BB
Peter
Edit: in the master POM I have
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.1</version>
<scope>compile</scope>
</dependency>
as a managed dependency. The module jar has the dependency as follows:
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</dependency>
The war module has no dependency to javax.mail.
Edit2:
I do override the war plugin in the master pom like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1</version>
<configuration>
<warName>${war.name}</warName>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
<manifestEntries>
<Implementation-Build>${buildNumber}</Implementation-Build>
</manifestEntries>
</archive>
</configuration>
</plugin>
Does your pom or master pom override the maven-war-plugin? It's possible to explicitly exclude artifacts from being put in the war:
http://maven.apache.org/plugins/maven-war-plugin/war-mojo.html#packagingExcludes
Also,
http://maven.apache.org/plugins/maven-war-plugin/war-mojo.html#warSourceExcludes
...I can't remember exactly the difference between the two excludes, and it doesn't really matter if you're not overriding the war plugin anyway.
If the javax.mail dependency is a dependency of one of your module, it should be included. However, if it is defined as an optional dependency, it will break the transitive dependency mechanism.
In others words, if in your module, you have that definition:
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.1</version>
<optional>true</optional>
</dependency>
If this is the case, simply remove this <optional>true</optional> statement.

maven dependencies groovy

I'm running a project that has a dependency on groovy 1.7-beta-1. The gmaven plugin uses groovy version 1.6 as a dependency. In my pom, I specify in the dependency management section the grooyv-all version as :
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>1.7-beta-1</version>
</dependency>
</dependencies>
</dependencyManagement>
Yet when I run maven in debug mode I see that groovy 1.6 is being used for a dependency to the gmaven plugin. I thought my dependency management section would override this so they all use 1.7-beta-1, but I'm getting errors due to the different groovy versions. any help here would be appreciated.
thanks,
Jeff
Here's a refined version of Pascal's answer. I upgraded the main plugin version to 1.2, the dependency to Groovy 1.7, and wrapped it all in a pluginManagement tag so that it will nicely leverage the inheritance model.
Keep in mind that the 1.3-SNAPSHOT of the GMaven plugin has already begun using the 1.7-rc2 Groovy provider.
<!-- I wrapped everything in a plugin management section so that this can be neatly inherited across all your poms -->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<!-- Notice I upgraded it to 1.2 -->
<!-- Details here http://repo1.maven.org/maven2/org/codehaus/gmaven/gmaven-plugin/1.2/gmaven-plugin-1.2.pom -->
<version>1.2</version>
<dependencies>
<dependency>
<groupId>org.codehaus.gmaven.runtime</groupId>
<artifactId>gmaven-runtime-1.7</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
Overriding a dependency used by a plugin is a nice ability that was actually introduced by Maven 2.0.9.
To do so, at least with a plugin that you are using as a normal build plugin - as opposed to a report which is not the case with the the gmaven-plugin so I won't cover this case here - simply add a dependency block inside the plugin block, like this (this is a sample so versions may be inaccurate):
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<goals>
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>1.7-beta-1</version>
</dependency>
</dependencies>
</plugin>
As long as the new version of the dependency is "API compatible" with the version the plugin was linked against, you should be ok. If not, then you'll obviously have to upgrade to a newer version of the plugin compatible with the new API (i.e. likely using it as dependency), which is what you did.
To make gmaven accurately picks the right runtime is by configuring the "providerSelection" value, e.g.
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<configuration>
<providerSelection>1.7</providerSelection>
</configuration>
FYI, for the groovy:providers mojo, these are the configurations it expects (I extracted them by debugging to org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(List, Stack, MavenSession, MavenProject) (look for XmlPlexusConfiguration):
<configuration>
<remoteRepositories implementation="java.util.List">${project.pluginArtifactRepositories}</remoteRepositories>
<project implementation="org.apache.maven.project.MavenProject">${project}</project>
<artifactRepository implementation="org.apache.maven.artifact.repository.ArtifactRepository">${localRepository}</artifactRepository>
<pluginArtifactMap implementation="java.util.Map">${plugin.artifactMap}</pluginArtifactMap>
<providerSelection implementation="java.lang.String">${gmaven.runtime}</providerSelection>
</configuration>
You need to add a similar 1.7 dependency to the dependencies of the plugin in a similarly structured <plugin> or <pluginManagement> section. Your dependency management section you are adding is proper, but does not affect the plugin dependencies. I'll try to review this reply and post an example later when I'm back at my desk.

Maven test dependency in multi module project

I use maven to build a multi module project. My module 2 depends on Module 1 src at compile scope and module 1 tests in test scope.
Module 2 -
<dependency>
<groupId>blah</groupId>
<artifactId>MODULE1</artifactId>
<version>blah</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
This works fine. Say my module 3 depends on Module1 src and tests at compile time.
Module 3 -
<dependency>
<groupId>blah</groupId>
<artifactId>MODULE1</artifactId>
<version>blah</version>
<classifier>tests</classifier>
<scope>compile</scope>
</dependency>
When I run mvn clean install, my build runs till module 3, fails at module 3 as it couldn't resolve the module 1 test dependency. Then I do a mvn install on module 3 alone, go back and run mvn install on my parent pom to make it build. How can I fix this?
I have a doubt about what you are trying to do but but I'll assume you want to reuse the tests that you have created for a project (module1) in another. As explained in the note at the bottom of the Guide to using attached tests:
Note that previous editions of this guide suggested to use <classifier>tests</classifier> instead of <type>test-jar</type>. While this currently works for some cases, it does not properly work during a reactor build of the test JAR module and any consumer if a lifecycle phase prior to install is invoked. In such a scenario, Maven will not resolve the test JAR from the output of the reactor build but from the local/remote repository. Apparently, the JAR from the repositories could be outdated or completely missing, causing a build failure (cf. MNG-2045).
So, first, to package up compiled tests in a JAR and deploy them for general reuse, configure the maven-jar-plugin as follows:
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Then, install/deploy the test JAR artifact as usual (using mvn install or mvn deploy).
Finally, to use the test JAR, you should specify a dependency with a specified type of test-jar:
<project>
...
<dependencies>
<dependency>
<groupId>com.myco.app</groupId>
<artifactId>foo</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
...
</project>
Regarding to my comment to Pascals question i think i have found a stuitable answer :
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
<phase>test-compile</phase>
</execution>
</executions>
<configuration>
<outputDirectory>${basedir}\target</outputDirectory>
</configuration>
</plugin>
</plugins>
The main difference here as you see here is the <phase> tag.
I will create the test-jar and it will be available in the compile phase of the tests and not only after the package phase.
Works for me.