178

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?

Greg Kopff
  • 15,945
  • 12
  • 55
  • 78
  • 1
    Check out [this answer](http://stackoverflow.com/a/1733745/966590). I think it should help you. – Andrew Logvinov Feb 06 '13 at 06:31
  • 9
    For future readers: [Maven Guide to using attached tests](http://maven.apache.org/guides/mini/guide-attached-tests.html) – Greg Kopff Feb 06 '13 at 06:36
  • @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 Feb 06 '13 at 06:42
  • 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 Feb 06 '13 at 06:58

2 Answers2

230

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.

Community
  • 1
  • 1
Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
  • 2
    regarding "Your Consumer project would then depend upon both the normal Data JAR artifact, plus the additional test-jar artifact" part, when I adding both the dependencies of data into consumer (let's say my artifacts named data & consumer as well) pom, without specific versions specification, the pom got error. Why is that happen? – Johnny Aug 20 '15 at 13:17
  • @StasS probably best you open a separate question about that. – Duncan Jones Aug 21 '15 at 11:39
  • 1
    Did it :) http://stackoverflow.com/questions/32119591/sharing-src-test-classes-with-maven-without-version-specification-for-test-jar – Johnny Aug 21 '15 at 12:57
1

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.

matsev
  • 32,104
  • 16
  • 121
  • 156
  • 1
    If I understand you, you're suggesting that any tests that use `SampleDataHelper` be moved from either the `data` module or the `consumer` module (as appropriate) into `data-test`. Unfortunately I don't find this a very "neat" solution as it moves my tests out of the module they test, and into a different one. (Strictly speaking, you only said to move the `data` tests, but I think I'd find myself moving both for consistency). But thank you for your answer. :-) – Greg Kopff Feb 06 '13 at 06:48
  • 1
    Yep, you understood me correctly. And arguably, it's more of a quick solution than a neat one. :-) – matsev Feb 06 '13 at 07:48
  • I would imagine the circular dependencies would remain. Assuming that the tests in question exercise the classes defined in the Data project, there would still need to be a reference back to the Data project from the Data-Test project. – Duncan Jones Feb 06 '13 at 07:49
  • 1
    @DuncanJones Sorry, there was a small typo in my post. The point I'm trying to make is that the `data-test` module should depend on the `data` module (and not the other way around). To avoid the circular dependency, all tests that currently reside in the `data` module that uses the `SampleDataHelper` must be moved to the `data-test` module. – matsev Feb 06 '13 at 08:15
  • Gotcha, that makes more sense. – Duncan Jones Feb 06 '13 at 09:47