Search code examples
compilationmaven-3integration-testingmulti-modulemaven-failsafe-plugin

Maven integration-test phase not binding to Failsafe


Primary Goal

To use command line to both compile and run integration tests in two peer modules of a multi-module repository following Maven's Standard Directory Layout:

module
    |_src
    |____it          integration-test
    |____main
    |____test      unit-test

update: Turns out, putting IT int tests in the "src / it" folder is not Maven's convention. "src / it" is intended for maven-plugin specific integration tests. Although, "src / it" can certainly be configured for IT int test's - if you need configuration over convention.

Intro

I have multi-module repository whose modules are inheriting from parent POMs (project's, and Spring related). I can't compile or run integration tests from command line starting from a "fresh" mvn clean, but I can get IntelliJ to compile all sources and run all tests (as Maven modules) - after which, int tests will also run at command line despite not having Failsafe bound to phase (sorta makes sense though). I can not pin down what is causing conflict at command line, if anything. Have searched this problem to my capacity's end, and -- yes -- I have tried pretty much every thing I could google, but to no avail. My POMs are defined herein as the current state after all previous attempted changes.

When issuing mvn help:describe -Dcmd=install on core module, it shows the Failsafe plugin (otherwise defined in my POM) is not being bound to the respective phase(s). This might explain why I can't run integration test, but not why it fails to be bound since it's defined in POM. Also, it does not explain why the int-test source is not compiling, as I am currently understanding int-test compilation to be done by the compiler plugin under the test-compile phase since there is no int-test-compile phase in a Maven lifecycle. Is this correct or is this also done in integration-test phase?

Maven help output

Suppose I mvn clean install module-parent. Then,

~$: pwd
/repo/module-core
~$: mvn help:describe -Dcmd=install
[INFO] 'install' is a phase corresponding to this plugin:
org.apache.maven.plugins:maven-install-plugin:2.4:install
It is a part of the lifecycle for the POM packaging 'jar'. This lifecycle includes the following phases:
* validate: Not defined
* initialize: Not defined
* generate-sources: Not defined
* process-sources: Not defined
* generate-resources: Not defined
* process-resources: org.apache.maven.plugins:maven-resources-plugin:2.6:resources
* compile: org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
* process-classes: Not defined
* generate-test-sources: Not defined
* process-test-sources: Not defined
* generate-test-resources: Not defined
* process-test-resources: org.apache.maven.plugins:maven-resources-plugin:2.6:testResources
* test-compile: org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile
* process-test-classes: Not defined
* test: org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test
* prepare-package: Not defined
* package: org.apache.maven.plugins:maven-jar-plugin:2.4:jar
* pre-integration-test: Not defined
* integration-test: Not defined
* post-integration-test: Not defined
* verify: Not defined
* install: org.apache.maven.plugins:maven-install-plugin:2.4:install
* deploy: org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy

Project structure overview

MainRepo
    |_ module-parent provided below
    |____ pom.xml
    |
    |_ module-core provided below
    |____ pom.xml
    |
    |_ module-backend (spring)
    |____ pom.xml
    |
    |_ module-frontend (angular2)
    |____ pom.xml

module-parent / pom.xml

<project>
    <!-- ... -->
    <groupId>my.apps.module</groupId>
    <artifactId>module-parent</artifactId>
    <version>0.1.0</version>
    <packaging>pom</packaging>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
    </parent>
    <modules>
        <module>../module-core</module>
        <module>../module-backend</module>
    </modules>
    <!-- ... -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>2.20</version>
                <executions>
                    <execution>
                        <id>module-parent-failsafe-it</id>
                        <phase>integration-test</phase>
                        <goals>
                            <goal>integration-test</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>module-parent-failsafe-verify</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

module-core / pom.xml

<project>
    <!-- ... -->
    <groupId>my.apps.module</groupId>
    <artifactId>module-core</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>my.apps.module</groupId>
        <artifactId>module-parent</artifactId>
        <version>0.1.0</version>
    </parent>
    <!-- ... -->
</project>

Other details / edits

Also meant to mention I reviewed the effective POM. It looks fine, but I'm not expert in Maven. Spring parent POM || Springs parent's parent POM is correctly setting the Failsafe plugin, so core-module -- I believe -- should be inheriting from that.


Solution

  • I assumed Failsafe not showing up in ..help:describe.. next to respective phases was root of my issue, but it turns out it was not (see answer for failsafe not binding to X or Y ). The setup of two test types (int/unit) between two different source locations (src/it and src/test) was the problem, and it appears to be a common configuration pain when using Maven. This is because it goes against the convention for how Maven assumes a project will be setup.

    In order to achieve the use of two different source folders for tests, I found [Kainulainen-2012] who demonstrates the use of [(org.codehaus.mojo:build-helper-maven-plugin)] which configures executions with additional sources for use during compilation. This solves the primary goal as defined above albeit in a non-conventional way while also introducing other problems. Alternatively, using Maven's convention would only require moving Integration tests into the "src/test" location of each module and possibly updating test names. I did not experience additional problems this way, and I found it to be the simpler solution.

    Solution 1 : Conventional

    1. Move Integration test to "src/test" classPath for each module.
    2. Give names to integration test which include "IT" [Failsafe default name convention]
    3. mvn install parent -> core -> backend modules

    Solution 2 : Non-conventional

    1. Add build-helper-maven-plugin to parent pom.xml under module-parent.
    2. mvn install parent -> core -> backend modules

    module-parent / pom.xml:

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <version>3.0.0</version>
                <executions>
                    <execution>
                        <id>add-integration-test-sources</id>
                        <phase>generate-test-sources</phase>
                        <goals>
                            <goal>add-test-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>src/it/java</source>
                            </sources>
                        </configuration>
                    </execution>
                    <execution>
                        <id>add-integration-test-resources</id>
                        <phase>generate-test-resources</phase>
                        <goals>
                            <goal>add-test-resource</goal>
                        </goals>
                        <configuration>
                            <resources>
                                <resource>
                                    <filtering>true</filtering>
                                    <directory>src/it/resources</directory>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- ... -->
        </plugins>
    </build>