We use Maven as our internal build tool for our Java projects, and most of time it works great. But recently, when trying to separate the execution of our integration tests from our unit tests, I ran into an unexpected hurdle.

Our internal code is a multi-module project, where each module provides its set of unit tests and integration tests for our internal build to execute. If the tests are successful (among other things), then each module is deployed as a snapshot JAR to our internal Nexus repository. Deploying snapshots allows our developers to work on other areas of our project’s code-base without having to build all internal dependencies locally.

Now, we need our internal build to be a) fast and b) reliable as we commit changes frequently throughout the day, which means we want to be building & deploying code frequently throughout the day as well. As you would guess, this is exactly the opposite of what integration tests are: slow (non-millisecond execution times) and unreliable.

While Maven distinguishes between unit tests and integration tests, it has not excluded the latter during its default build cycle. So, when running “mvn clean deploy”, Maven will execute all the build phases underneath it (..compile->test->..->integration-test->..->install->deploy). For us, this means that every time we execute an internal build, each module’s integration tests will be run as a result (no thanks).

So, I wanted to know how I could run our modules’ integration tests separately from our regular build. There were quite a few questions on Stack Overflow around this, but none of the responses were 100% accurate. So, after a bunch of trial-and-error to get Maven to behave how I wanted, I figured I’d share our solution.

Note: Solution assumes that Integration tests conform to the naming convention of *IntegrationTest.java

1) Exclude integration tests from the regular build test phase. Include the following in the build section of your POM:

       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <groupId>org.apache.maven.plugins</groupId>
         <version>2.9</version>
         <configuration>
             <skip>false</skip>
             <useFile>false</useFile>
             <argLine>-Xms1024m -Xmx1024m -XX:MaxPermSize=512m</argLine>
             <excludes>
                 <exclude>**/*IntegrationTest.java</exclude>
             </excludes>
         </configuration>
       </plugin>

Now our regular build on our CI environment can run the standard “mvn clean deploy” fast and efficiently. The only tests that will be run will be unit tests.

2) Create a separate Maven profile that will only execute integration tests (and exclude all unit tests):

<profiles>
    <profile>
        <id>integration-test-builder</id>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <groupId>org.apache.maven.plugins</groupId>
                    <version>2.9</version>
                    <configuration>
                        <skip>false</skip>
                        <useFile>false</useFile>
                        <argLine>-Xms1024m -Xmx1024m -XX:MaxPermSize=512m</argLine>
                        <excludes>
                            <exclude>none</exclude>
                        </excludes>
                        <includes>
                            <include>**/*IntegrationTest.java</include>
                        </includes>
                    </configuration>
                    <executions>
                        <execution>
                             <id>integration-tests</id>
                              <phase>integration-test</phase>
                            <goals>
                                <goal>test</goal>
                            </goals>
                          </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>   

This profile can be run as such: mvn clean integration-test -P integration-test-builder. We can have a separate build job on our CI environment whose only purpose is to run integration tests once per day using this profile.