Integration testing with Maven has always been a bit painful. Often the integration tests are scattered alongside with unit tests or a different module has been created for them. Both of these approaches are a bit disturbing.
Scattering integration tests in the same directory structure with unit tests is an awful idea because integration tests and unit tests are completely different creatures, and this approach forces us to mix them together. This a minor annoyance but this approach has a nasty side effect: running unit tests from IDE becomes a pain in the ass. When the tests are executed, our IDE wants to run all tests found from the test directory, which means that both unit tests and integration tests are executed. If we are “lucky”, this means that the tests take a bit longer to run, but often this means that the integration tests fails every time. Not nice, huh?
The second approach is a bit more feasible but to be honest, it feels like a total overkill. This forces us to turn our project in to a multi module project only because we want separate our integration from our unit tests. Also, if our project is already a multi module project and we want to write integration tests for more than one module, we are screwed. Of course we can always create a separate integration test module for each tested module, but it would be less painful to shoot ourselves to a leg instead.
This blog entry describes how we can separate the source directories of unit tests and integration tests and keep them in the same module. The requirements of our build process are following:
- Integration and unit tests must have separate source folders.
- Integration and unit tests must have separate configuration files.
- Only unit tests are run by default.
- It must be possible to run only integration tests.
- Failing integration tests must cause build failure.
We can implement these requirements by following these steps:
- Create a separate profile for development and integration testing.
- Create profile specific configuration files.
- Add a new source directory to our build.
- Configure the Surefire Maven plugin.
- Configure the Failsafe Maven plugin.
These steps are explained with more details in following.
Creating New Profiles for Development and Integration Testing
First we have to create two profiles: a profile that is used for development and a profile that is used for running the integration tests. We have two goals: First, we want to disable integration tests when development profile is used. Second, we want to disable unit tests when the integration test profile is used. In order to achieve these goals, we will introduce three new properties:
- The skip.unit.tests property specifies whether unit tests are skipped or not.
- The skip.integration.tests property specifies if integration tests are skipped or not.
- The build.profile.id property identifies the used profile.
The configuration of the new build profiles has two steps:
- Add the default values of the specified properties to our POM file.
- Create the new profiles and extend the default property values in the integration-test profile.
The configuration of the Maven profiles is given in following:
<!-- Used to locate the profile specific configuration file. -->
<!-- Only unit tests are run by default. -->
<!-- Used to locate the profile specific configuration file. -->
<!-- Only integration tests are run. -->
Creating Profile Specific Configuration Files
In order to create the profile specific configuration files, we have to use a concept called resource filtering. If you are not familiar with this concept, you might want to check out my blog entry, which explains how profile specific configuration files are created. The configuration of resource filtering has two steps:
- Configure the location of the configuration file that contains profile specific configuration (The value of the build.profile.id property identifies the used profile).
- Configure the location of the resource directory.
The required Maven configuration is given in following:
Adding New Source Directory for Integration Tests
Since Maven does not support multiple test source directories, we have to use the Build Helper Maven plugin. This plugin has a goal called add-test-source that is used to add a test source directory to a Maven build. In order to add the source directory of our integration tests to our Maven build, we have to follow these steps:
- Ensure that the add-test-source goal of Builder Helper Maven plugin is executed at Maven’s generate-test-source lifecycle phase.
- Configure the source directory of our integration tests.
The configuration of the Build Helper Maven plugin is given in following:
<!-- States that the plugin's add-test-source goal is executed at generate-test-sources phase. -->
<!-- Configures the source directory of integration tests. -->
Configuring the Surefire Maven Plugin
We will use the Surefire Maven plugin to run our unit tests. We can configure this plugin by following these steps:
- Configure the plugin to skip unit tests if the value of the skip.unit.tests property is true.
- Exclude our integration tests. We will assume that the name of each integration test class starts with a string “IT”.
The configuration of the Surefire Maven plugin is given in following:
<!-- Skips unit tests if the value of skip.unit.tests property is true -->
<!-- Excludes integration tests when unit tests are run. ß-->
Configuring the Failsafe Maven Plugin
The Failsafe Maven plugin is used to execute our integration tests. We can configure it by following these steps:
- Configure the plugin to run its integration-test and verify goals.
- Configure the plugin to skip integration tests if the value of the skip.integration.tests property is true.
The configuration of the Failsafe Maven plugin looks following:
<!-- States that both integration-test and verify goals of the Failsafe Maven plugin are executed. -->
<!-- Skips integration tests if the value of skip.integration.tests property is true -->
Running Unit and Integration Tests
That is all. We have now configured our pom.xml and its time to run our tests. The commands used to run both unit and integration tests are explained in following:
- We can run our unit tests by executing a command mvn clean test on command line.
- Our integration tests are executed by running a command mvn clean verify -P integration-test on command line. If we want to run our integration tests from our IDE, we have to manually mark the source directory of our integration tests as a test source root directory.
I have also created a very simple example project that contains one integration test and one unit test. This example project can be used to demonstrate the concept that is described in this blog entry. As always, the example project is available at Github.