139
votes

I have a multi-module Maven project. For the sake of this example, consider two modules:

  • data
  • consumer

Module consumer has module data as a dependency.

Module data declares a bunch of core classes. There are tests under src/test that use them. These tests require some long-winded object creation, so I have a class with some utility methods in it to create these objects. This utility class (SampleDataHelper) is in the src/test hierarchy.

I also have some tests in the consumer module that need to create some of these long-winded objects. I want to use my SampleDataHelper class (defined in data src/test) in tests that reside in my consumer src/test tree. Unfortunately, even though data is a dependency of consumer, consumer can't see the classes that exist under data src/test.

To combat this, I thought I might create another module (data-test), and move SampleDataHelper to it under src/main. Then I would include data-test as a test scope dependency of data. Unfortunately, this introduces a circular dependency: data uses data-test, but data-test also requires data.

The only solution I've come up with is to place SampleDataHelper under data src/main under a test package and hope that no real application code ever calls it.

How can I share my SampleDataHelper class between modules without putting it under src/main?

2
Check out this answer. I think it should help you.Andrew Logvinov
@AndrewLogvinov: wouldn't your linked answer require a "two-step" build? To first build and deploy one module (data) before I can even compile my second module (consumer).Greg Kopff
I think you might come across some problems if you use mvn package, but it should work just fine in a single step build when you use mvn install or mvn deploy. Just a quick note. In one of our large projects we have a wrapper over junit's TestBase and it's located in src/main which I don't consider to be a good idea either.Andrew Logvinov

2 Answers

180
votes

Your Consumer project depends upon your Data project, therefore we are happy that Data must be built prior to Consumer. As a result, using the techniques suggested in the comments, I would ensure your Data project contains all the test code that you wish to share and configure the POM to produce a test JAR:

<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>

Your Consumer project would then depend upon both the normal Data JAR artifact, plus the additional test-jar artifact, with test scope of course:

<dependency>
  <groupId>com.foo</groupId>
  <artifactId>data</artifactId>
  <version>1.0</version>
  <type>test-jar</type>
  <scope>test</scope>
</dependency>

I've used this approach on many occasions and it works well.

1
votes

So the problem is that (some) tests in the data module depend on the SampleDataHelper class? You can move the SampleDataHelper class to src/main of the data-test module, if you at the same time move the tests (that depend on the specific class) to the src/test of the data-test module. Consequently, there would be no more circular dependencies.