How to setup Maven dependencies between test folders in two projects? - java

I have a project setup like this:
parent
|_____project-a
|_____project-b
I want classes in the test folder of project-b to resolve classes in the test folder of project-a.
Actually, I want to access both classes from the main folder and stuff from the test folder.
Is this possible?
Thanks

You can build project A with the goal test-jar
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
Then include it with type test-jar in project B:
<dependency>
<groupId>com.example</groupId>
<artifactId>project-a</artifactId>
<type>test-jar</type>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>

Since content of test folder is not included into target for project it cannot be used outside.
The best way i think is to move common classes to project like 'project-testcommons' and use it in project-a and project-b with 'test' scope.

Related

Java: Can't find symbol: class name, when the class name in one of two packages with the same name [duplicate]

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.

JUnit categories with multi module project - Unable to load category

I want to include/exclude JUnit categorized tests. I have a marker interface StressTest defined in a common module. I am referencing StressTest in moduleA. I have the following maven-surefire-plugin in root pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<excludedGroups>com.mycompany.project.common.utils.StressTest</excludedGroups>
</configuration>
</plugin>
When running mvn test I get the following while building another module.
Unable to load category: com.mycompany.project.common.utils.StressTest
Where should I write my StressTest interface?
In order for surefire to 'find' your #Category class it must be on the classpath produced from your Maven project's dependency tree.
This exception ...
Unable to load category: com.mycompany.project.common.utils.StressTest
... strongly implies that whatever artifact contains com.mycompany.project.common.utils.StressTest is not a declared dependency of your moduleA.
So, you'll need to add a dependency on whatever artifact contains com.mycompany.project.common.utils.StressTest to your moduleA. If the only purpose of this dependency is to provide the #Category class then it would make sense to make this dependency test scoped e.g.
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>common.utils</artifactId>
<version>...</version>
<scope>test</scope>
</dependency>
Furthermore, if com.mycompany.project.common.utils.StressTest is in the test tree rather than the main tree in your common utils module then you will need to create a JAR containing the common utils module's test classes. You can do this by adding the following maven-jar-plugin declaration to the common utils' pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
You would then depend on this using <type>test-jar</type>in the dependency in your moduleA, for example:
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>common.utils</artifactId>
<version>...</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>

Importing testng classes when scope marked 'test'

I have a testng dependency in pom.xml with 'test' scope:
</dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
My folder layout is as follows:
src/test/java - test source folder
src/test/resources - test resources folder
When trying to import testng in classes created under src/test/java/ IntelliJ can not find testng.
First of all open Maven Projects tab and simply refresh to get in sync.
Secondly, open the project structure and check if your sources are marked correctly.
Without more info, this is what I would suggest.
I suspect you have src/test/java in one module/project and you would like to reuse it in other module/project? If that's correct you need to build and install your test jar (add to your source 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>
Then you can use it in other projects by adding maven dependency.

How to include tests in project B from dependent project A and have them recognized by Maven "as is"

I have a (Maven) project B dependent on project A. Project A packages its tests into a jar, as described here. Suppose I have a test class com.forelight.a.FooTest in projecet A. The class is visible on the test-scoped class path in project B, but is not automatically execute by mvn test. I can extend FooTest in project B's test/main/java directory like so:
package com.forelight.b;
public class FooBarTest extends com.forelight.a.FooTest {}
This does the job (mvn test runs this both command line and under eclipse) but feels kludgy.
Here is a working automated solution:
project A should also provide its test-sources jar
project B should import project A in test scope and also import project A test sources in test scope
project B would use the unpack-dependencies of the Maven Dependencies Plugin to automatically unpack the test-sources jar to a subfolder of the target folder (say project-a-test-sources)
project B would use the add-test-source goal of the Build Helper Maven Plugin to add automatically the unpacked sources as test sources in project A
Maven will then compile and run the added sources as part of project B tests
To achieve it, in project A add the following to the build section:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
This will actually create a new jar as part of the build providing test sources. Remember to install it via mvn install.
In project B, add the following to the dependencies:
<dependency>
<groupId>com.sample</groupId>
<artifactId>project-a</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sample</groupId>
<artifactId>project-a</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
<classifier>test-sources</classifier>
</dependency>
So that the classpath will be populated with project A, the second dependency is harmless, it will be used by the plugin execution below.
In project B, also add the following to the build section:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>unpack-test-sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includeGroupIds>com.sample</includeGroupIds>
<includeArtifactIds>project-a</includeArtifactIds>
<includeScope>test</includeScope>
<includeClassifiers>test-sources</includeClassifiers>
<outputDirectory>
${project.build.directory}/project-a-test-sources
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<id>add-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/project-a-test-sources</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
Here we are unpacking sources and adding them as test sources.
Maven will then automatically execute the added tests.
Few considerations on this approach:
It might look as kludgy as the approach you mentioned in your question, even though it would be automated and would not require to create new extension tests
It's definitely not something standard, but the original requirement also doesn't sound like a standard practice neither
You may have conflicts on test names or resources names (again, because it's not a standard approach)
You may not want to run these external tests as part of your default build, in this case you could move the configuration above to a Maven profile, say run-project-a-tests and execute them only upon desire via -Prun-project-a-tests. This will also make your default build faster (and more standard).

Publish test utils from maven project

I created a library in maven that can be extended by implementing some interfaces. To test the default implementation I have written some hamcrest matchers that currently live in src/test/java.
However, I think they might be useful for users of the library if they want to test their customization.
So how can I make them available? Moving them to src/main would require to make hamcrest a runtime dependency and I don't want that.
There is a way to create a test jar and install it into the repository using the command 'mvn jar:test-jar'. This jar can then be referenced by other projects using the test-jar modifier in the dependency block.
If you want to have this jar built and installed as part of your your normal 'mvn install' build add the following plugin config to your pom:
From http://maven.apache.org/guides/mini/guide-attached-tests.html
<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 other projects can reference the test jar as follows:
<dependency>
<groupId>com.myco.app</groupId>
<artifactId>foo</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
As you said, move it to src/main in a new project. Let that project only be used in a test dependency and you don't pollute your module's classpath.
It sounds like you need to move them to their own project and release it. From there you can determine in the original project what scope you'd like.

Categories