Search code examples
javaintegration-testingmaven-3maven-pluginmaven-failsafe-plugin

Maven Integration-Test how to set-up POM correctly for different Profiles


I am having problems controlling how Maven copies resource files during the Dev Compile/Test steps and the Integration-Test Compile/Verify steps.

I've created two Profiles in Maven, Dev and Integration-Test. I've created a config.properties file for each profile. In my src/test/resources and src/integration/resources locations I have a myappconfig.properties file. I would like it so that the correct values from the respective profile config.properties are overlaid into these files and copied to the target/test-classes during the compile/test/verify steps for each profile (Dev/Integration-Test).

I am getting unwanted behaviour when running the Dev profile for the Compile and Test goals and unwanted behaviour for the Integration-Test profile during the Compile goal. I have summarised the expected and actual behaviour in the table below as its easier than writing it all out. I am also including the POM file listing and screenshots from my Intellij.

It seems like I need a way to stop the build-helper-maven-plugin from firing when the DEV profile is selected. Is there a way to set that up in the same way as I am able to skip the Integration Tests when running the DEV tests? or is the problem something else ?

Contents of config.property files

1) profiles/dev/config.properties

server.message=hello_from_dev

2) profiles/integration-test/config.properties

server.message=hello_from_integration_test

3) src/test/resources/myappconfig.properties

## dev-test config.${build.profile.id}server.message=${server.message}

4) src/integration-test/resources/myappconfig.properties

## integration-test config.${build.profile.id}server.message=${server.message}

Summary Table of Issues

enter image description here

POM Listing

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.stackoverflow</groupId>
  <artifactId>mavenintegrationtest</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>mavenintegrationtest</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <filters>
      <!--
                    Ensures that the config.properties file is always loaded from the
                    configuration directory of the active Maven profile.
    
                -->
      <filter>${basedir}/profiles/${build.profile.id}/config.properties</filter>
    </filters>

    <resources>
      <!--
                    Placeholders that are found from the files located in the configured resource
                    directories are replaced with the property values found from the profile
                    specific configuration file.
                -->
      <resource>
        <filtering>true</filtering>
        <directory>src/main/resources</directory>
      </resource>
    </resources>

    <testResources>
      <!--
                      <testResource>
                        <filtering>true</filtering>
                        <directory>src/integration-test/resources</directory>
                      </testResource>
                -->
      <testResource>
        <filtering>true</filtering>
        <directory>src/test/resources</directory>
      </testResource>
    </testResources>

    <pluginManagement>
      <!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>build-helper-maven-plugin</artifactId>
          <version>3.0.0</version>
          <executions>
            <!-- Add executions here -->
            <!-- Add a new source directory to our build -->
            <execution>
              <id>add-integration-test-sources</id>
              <phase>generate-test-sources</phase>
              <goals>
                <goal>add-test-source</goal>
              </goals>
              <configuration>
                <!-- Configures the source directory of our integration tests -->
                <sources>
                  <source>src/integration-test/java</source>
                </sources>
              </configuration>
            </execution>
            <!-- Add a new resource directory to our build -->
            <execution>
              <id>add-integration-test-resources</id>
              <phase>generate-test-resources</phase>
              <goals>
                <goal>add-test-resource</goal>
              </goals>
              <configuration>
                <!-- Configures the resource directory of our integration tests -->
                <resources>
                  <!--
                                            Placeholders that are found from the files located in the configured resource
                                            directories are replaced with the property values found from the profile
                                            specific configuration file.
                                        -->
                  <resource>
                    <filtering>true</filtering>
                    <directory>src/integration-test/resources</directory>
                  </resource>
                </resources>
              </configuration>
            </execution>
          </executions>
        </plugin>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
          <configuration>
            <!-- Skips unit tests if the value of skip.unit.tests property is true -->
            <skipTests>${skip.unit.tests}</skipTests>
            <!-- Excludes integration tests when unit tests are run -->
            <excludes>
              <exclude>**/IT*.java</exclude>
            </excludes>
          </configuration>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-failsafe-plugin</artifactId>
          <version>3.0.0-M3</version>
          <executions>
            <!--
                                Invokes both the integration-test and the verify goals of the
                                Failsafe Maven plugin
                            -->
            <execution>
              <id>integration-tests</id>
              <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
              </goals>
              <configuration>
                <!--
                                        Skips integration tests if the value of skip.integration.tests
                                        property is true
                                    -->
                <skipTests>${skip.integration.tests}</skipTests>
              </configuration>
            </execution>
          </executions>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-failsafe-plugin</artifactId>
        <version>3.0.0-M3</version>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>build-helper-maven-plugin</artifactId>
        <version>3.0.0</version>
      </plugin>
    </plugins>
  </build>
  <!-- Profile configuration -->
  <profiles>
    <!-- The configuration of the development profile -->
    <profile>
      <id>dev</id>
      <!-- The development profile is active by default -->
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <!--
                        Specifies the build.profile.id property that must be equal than the name of
                        the directory that contains the profile specific configuration file.
                        Because the name of the directory that contains the configuration file of the
                        development profile is dev, we must set the value of the build.profile.id
                        property to dev.
                    -->
        <build.profile.id>dev</build.profile.id>
        <!--
                        Only unit tests are run when the development profile is active
                     -->
        <skip.integration.tests>true</skip.integration.tests>
        <skip.unit.tests>false</skip.unit.tests>
      </properties>
    </profile>
    <!-- The configuration of the integration-test profile -->
    <profile>
      <id>integration-test</id>
      <properties>
        <!--
                        Specifies the build.profile.id property that must be equal than the name of
                        the directory that contains the profile specific configuration file.
                        Because the name of the directory that contains the configuration file of the
                        production profile is prod, we must set the value of the build.profile.id
                        property to prod.
                    -->
        <build.profile.id>integration-test</build.profile.id>
        <!--
                        Only integration tests are run when the integration-test profile is active
                    -->
        <skip.integration.tests>false</skip.integration.tests>
        <skip.unit.tests>true</skip.unit.tests>
      </properties>
    </profile>
  </profiles>

</project>

Intellij Screenshots

enter image description here enter image description here


Solution

  • I've had a go at changing my POM using the tip that @Jorge Campos gave me. I think it works ok. Please find below incase it can help someone. Thank you for your advice @Jorge Campos - really the points should go to you but I cant give them for a comment.

    <?xml version="1.0" encoding="UTF-8"?>
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.stackoverflow</groupId>
        <artifactId>maven-compilerpluginoverride</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <name>mavencompilerpluginoverride</name>
        <!-- FIXME change it to the project's website -->
        <url>http://www.example.com</url>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>1.7</maven.compiler.source>
            <maven.compiler.target>1.7</maven.compiler.target>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.11</version>
            </dependency>
        </dependencies>
    
        <build>
    
            <filters>
                <!--
                    Ensures that the config.properties file is always loaded from the
                    configuration directory of the active Maven profile.
                -->
                <filter>profiles/${build.profile.id}/config.properties</filter>
            </filters>
    
            <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
                <plugins>
                    <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
                    <plugin>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>3.8.0</version>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <version>3.0.0-M1</version>
                        <configuration>
                            <!-- Skips unit tests if the value of skip.unit.tests property is true -->
                            <skipTests>${skip.unit.tests}</skipTests>
                            <!-- Excludes integration tests when unit tests are run -->
                            <excludes>
                                <exclude>**/IT*.java</exclude>
                            </excludes>
                        </configuration>
                    </plugin>
                    <plugin>
                        <artifactId>maven-clean-plugin</artifactId>
                        <version>3.1.0</version>
                    </plugin>
                    <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
                    <plugin>
                        <artifactId>maven-resources-plugin</artifactId>
                        <version>3.0.2</version>
                    </plugin>
    
                    <plugin>
                        <artifactId>maven-jar-plugin</artifactId>
                        <version>3.0.2</version>
                    </plugin>
                    <plugin>
                        <artifactId>maven-install-plugin</artifactId>
                        <version>2.5.2</version>
                    </plugin>
                    <plugin>
                        <artifactId>maven-deploy-plugin</artifactId>
                        <version>2.8.2</version>
                    </plugin>
                    <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
                    <plugin>
                        <artifactId>maven-site-plugin</artifactId>
                        <version>3.7.1</version>
                    </plugin>
                    <plugin>
                        <artifactId>maven-project-info-reports-plugin</artifactId>
                        <version>3.0.0</version>
                    </plugin>
                </plugins>
            </pluginManagement>
    
            <plugins>
    
            </plugins>
    
        </build>
    
        <profiles>
            <!-- The Configuration of the development profile -->
            <profile>
                <id>dev</id>
                <activation>
                    <activeByDefault>true</activeByDefault>
                </activation>
                <properties>
                    <!--
                        Specifies the build.profile.id property that must be equal than the name of
                        the directory that contains the profile specific configuration file.
                        Because the name of the directory that contains the configuration file of the
                        development profile is dev, we must set the value of the build.profile.id
                        property to dev.
                    -->
                    <build.profile.id>dev</build.profile.id>
                    <!--
                        Only unit tests are run when the development profile is active
                    -->
                    <skip.integration.tests>true</skip.integration.tests>
                    <skip.unit.tests>false</skip.unit.tests>
                </properties>
                <build>
                    <resources>
                        <!--
                            Placeholders that are found from the files located in the configured resource
                            directories are replaced with the property values found from the profile
                            specific configuration file.
                        -->
                        <resource>
                            <filtering>true</filtering>
                            <directory>src/main/resources</directory>
                        </resource>
                    </resources>
                    <testResources>
                        <testResource>
                            <directory>src/test/java</directory>
                            <excludes>
                                <exclude>**/*.java</exclude>
                            </excludes>
                        </testResource>
                        <testResource>
                            <directory>src/integration-test/java</directory>
                            <excludes>
                                <exclude>**/*.java</exclude>
                            </excludes>
                        </testResource>
                        <testResource>
                            <filtering>true</filtering>
                            <directory>src/test/resources</directory>
                        </testResource>
                    </testResources>
                </build>
            </profile>
            <!-- The Configuration of the integration-test profile -->
            <profile>
                <id>integration-test</id>
                <properties>
                    <!--
                        Specifies the build.profile.id property that must be equal than the name of
                        the directory that contains the profile specific configuration file.
                        Because the name of the directory that contains the configuration file of the
                        integration-test profile is integration-test, we must set the value of the
                        build.profile.id property to integration-test.
                    -->
                    <build.profile.id>integration-test</build.profile.id>
                    <!--
                        Only integration tests are run when the integration-test profile is active
                    -->
                    <skip.integration.tests>false</skip.integration.tests>
                    <skip.unit.tests>true</skip.unit.tests>
                </properties>
                <build>
                    <resources>
                        <resource>
                            <directory>src/test/</directory>
                            <excludes>
                                <exclude>**/*.java</exclude>
                            </excludes>
                        </resource>
                        <resource>
                            <filtering>true</filtering>
                            <directory>src/integration-test/resources</directory>
                        </resource>
                    </resources>
                    <testResources>
                    </testResources>
                    <plugins>
                        <plugin>
                            <groupId>org.codehaus.mojo</groupId>
                            <artifactId>build-helper-maven-plugin</artifactId>
                            <version>3.0.0</version>
                            <executions>
                                <!-- Add executions here -->
                                <!-- Add a new source directory to our build -->
                                <execution>
                                    <id>add-integration-test-sources</id>
                                    <phase>generate-test-sources</phase>
                                    <goals>
                                        <goal>add-test-source</goal>
                                    </goals>
                                    <configuration>
                                        <!-- Configures the source directory of our integration tests -->
                                        <sources>
                                            <source>src/integration-test/java</source>
                                        </sources>
                                    </configuration>
                                </execution>
                            </executions>
                        </plugin>
                        <plugin>
                            <groupId>org.apache.maven.plugins</groupId>
                            <artifactId>maven-failsafe-plugin</artifactId>
                            <version>3.0.0-M1</version>
                            <executions>
                                <!--
                                    Invokes both the integration-test and the verify goals of the
                                    Failsafe Maven plugin
                                -->
                                <execution>
                                    <id>integration-tests</id>
                                    <goals>
                                        <goal>integration-test</goal>
                                        <goal>verify</goal>
                                    </goals>
                                    <configuration>
                                        <!--
                                            Skips integration tests if the value of skip.integration.tests
                                            property is true
                                        -->
                                        <skipTests>${skip.integration.tests}</skipTests>
                                    </configuration>
                                </execution>
                            </executions>
                        </plugin>
                    </plugins>
    
                </build>
            </profile>
        </profiles>
    
    </project>

    screenshot showing the Dev Profile being used

    screenshot showing the Integration-Test Profile being used