hhwebdev
hhwebdev

Reputation: 61

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.

Upvotes: 0

Views: 1515

Answers (2)

hhwebdev
hhwebdev

Reputation: 61

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>

Upvotes: 0

hhwebdev
hhwebdev

Reputation: 61

Failsafe not binding to X or Y Phase.

where x = integration-test, and y = verify.

Using the output of mvn help:describe -Dcmd=install to determine binding seems more like a red herring. Just because plugin is not listed next to a phase in the output, does not mean plugin fails to execute during mvn install

Suppose you have a simple single-module project based strictly on Maven's expected conventions:

lone-module
    |_ src
        |_ main
            |_ java
                |_ Service.java
    |_ src
        |_ test
            |_ java
                |_ ServiceIT.java         int-test
                |_ ServiceTest.java     unit-test
    |_ pom.xml

And let pom.xml be defined as follows:

<project>
    <!-- ... -->
    <groupId>single.module.apps</groupId>
    <artifactId>lone-module</artifactId>
    <version>0.1.0</version>

    <dependencies>
        <!-- ... -->
    </dependencies>
</project>

Then, mvn install compiles both Unit and Integration tests (as observed in target / test-class / *), but it only runs the Unit tests (as observed at cmd line). Next, run mvn help-describe -Dcmd=install.

Notice "Not defined"

* integration-test: Not defined
* ...
* verify: Not defined

This could be reasoned as our not having defined maven-failsafe-plugin in our pom.xml. So, let pom.xml include said plugin:

<project>
    <!-- ... -->
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.20</version>
            <executions>
                <execution>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</project>

Then, mvn help-describe -Dcmd=install will still show output of "Not defined" for the X and Y phase.

But, mvn install will now also run the integration test(s) using the maven-failsafe-plugin.

[INFO] --- maven-failsafe-plugin:2.20:integration-test (default) @ lone-module ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running ServiceIT
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.388 s - in ServiceIT

This shows us that the X phase is executing the goal of failsafe-plugin, despite ..help:describe.. showing phase as "Not defined."

Upvotes: 1

Related Questions