We’ve now had two cases at work where we have created a set of junit tests, which we want to re-use in other maven modules. It is a two stage process, and there are a couple of options for how to run the tests in the project which imports them.
Creating re-usable tests
First, we create the tests in the ‘tester-module’. These are standard unit tests in src/test/java
. Of course, they must pass, or your project will not build. So you need some sample implementations of the what you are testing within that project. For ease of use, we put all the tests which will be exported into a single package.
To create a test-jar, which can be a dependency for other projects, add to the pom:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<executions>
<execution>
<id>test-jar</id>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<includes>
<include>**/exported_tests/*</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
This will generate a test-jar containing only the tests in the package specified.
Importing the tests
To import the test to the module which will use them, the following dependency is added.
<dependency>
<groupId>tester-group</groupId>
<artifactId>tester-module</artifactId>
<version>1.0</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
Running the tests
There are two ways of running the attached tests. They DO NOT get run automatically when you run mvn test
.
Method 1. Extracting the dependency
Adding the following to the pom will extract the test classes into target/test-classes, so that they all get run when you run mvn test
. This works well if you always want to run ALL the attached tests.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>process-test-classes</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>tester-group</groupId>
<artifactId>tester-module</artifactId>
<version>1.0</version>
<type>test-jar</type>
<outputDirectory>${project.build.directory}/test-classes</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
Method 2. Using test suites
If you want to run certain tests only, you can add a TestSuite to the module, and define which of the attached tests should be run as part of the test suite.
@RunWith(Suite.class)
@Suite.SuiteClasses({TestClass1.class, TestClass2.class})
public class TestSuite {
//nothing
}
An afterthought: testing the tests
In the situations where we are re-using our tests, the tests themselves become a critical component of our systems. We wanted to be able to test the tests too. We got round this by not including logic in the tests themselves. Instead, the test-module contains a set of ‘validators’, in src/main. We can then write tests for these ‘validators’ as usual. The tests in ‘exported_tests’ can then simply delegate to an appropriate validator, which we know has been tested.
assertTrue(validator.validate(classUnderTest));
The only difference this makes is that you have to add a normal dependency to the tester-module, as well as the test-jar dependency.
We’ve found this approach very useful, as we’re using maven and junit as a framework for testing other file resources. However I think it is useful for java code too, if you have a set of interfaces, and different implementations in different modules.
References:
http://maven.apache.org/guides/mini/guide-attached-tests.html
http://softwaremavens.blogspot.co.uk/2009/09/running-tests-from-maven-test-jar-in.html