Test Artifact Reuse in Maven

I’ve known that this feature was possible, but I only just recently hit the point of really wanting to do it.

When you have multiple maven projects — especially modules in a multiple module set-up — you sometimes want to reuse a test class from one module in another module.

Consider this example:

MyProjectRoot
  |
  +- MyProjectModel
  |      |
  |      +- src/main/java/
  |      |     |
  |      |     +- ca/intelliware/example/model
  |      |                 |
  |      |                 +- Person
  |      +- src/test/java/
  |      |     +- ca/intelliware/example/model
  |                        |
  |                        +- PersonBuilder
  |
  +- MyProjectWeb
         |
         +- src/main/java/
               |
               +- ca/intelliware/example/controller
                           |
                           +- PersonUpdateController

So imagine that you want test the PersonUpdateController in your web project. If you’re updating a Person, maybe you want to seed your test with an initially-populated Person object. It’s a simple thing to instantiate a Person and fill it up with data. But, hey, Deth’s been going on and on about Builder patterns, so maybe a PersonBuilder is a Good Thing to have.

Before long, I start finding myself needing my PersonBuilder in code used in multiple projects. I could, I suppose, have a test utilities module, and put it there. But it feels like it lives, more properly, with my model module.

Now Maven handles dependencies pretty well. But its default behaviour is to depend on the “main” (or “production-ready”) classes in another artifact.

I’ve known that it was possible to depend on test classes in Maven, but I hadn’t had a real need actually do it until this week. It didn’t take long to figure out (and I knew that the Foundation people had once mentioned that they do this). But here are the salient things.

First, in MyProjectModel, I add the following snippet to the POM:

<project>
   ...
   <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>
</project>

This snippet basically tells the Maven infrastructure that when I build, I should jar up the test classes and install/deploy/whatever those along with the main code.

Then, in MyProjectWeb, I add this dependency:

<dependency>
    <groupId>ca.intelliware.example</groupId>
    <artifactId>MyProjectModel</artifactId>
    <version>1.3-SNAPSHOT</version>
    <classifier>tests</classifier>
    <scope>test</scope>
  </dependency>

Notice the special “tests” classifier. This indicates that I want to depend on the classes put into the test jar. And, of course, I want to mark this as a dependency for test-purposes only, so I set my scope to be “test” as well.

And that does it. Eclipse’s idea of classpaths is very different than Maven’s, and one can trust Eclipse and end up with a situation that won’t build on the command line (or the build machine). But test dependency is possible, and pretty easy.

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply