How can I skip tests in maven install goal, while running them in maven test goal?

It sounds like you didn't understand the concept of the build life-cycle in Maven. If you run mvn install all life-cycle phases (including the install phase itself) run before the install phase. This means running the following phases:

  1. validate
  2. initialize
  3. generate-sources
  4. process-sources
  5. generate-resources
  6. process-resources
  7. compile
  8. process-classes
  9. generate-test-sources
  10. process-test-sources
  11. generate-test-resources
  12. process-test-resources
  13. test-compile
  14. process-test-classes
  15. test
  16. prepare-package
  17. package
  18. pre-integration-test
  19. integration-test
  20. post-integration-test
  21. verify
  22. install

which means in other words the test as well as integration-test life-cycle phases are included. So without any supplemental information it's not possible to change the behaviour as you wish it.

It could be achieved by using a profile in Maven:

 <project>
  [...]
  <profiles>
    <profile>
      <id>no-unit-tests</id>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
              <skipTests>true</skipTests>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>
  [...]
</project>

So your first requirement:

  1. If I run mvn install, I want all tests to compile, but I do not want to execute any.

can be achieved by using the following:

mvn -Pno-unit-test test
  1. If I run mvn test, I want all tests to compile, but execute only unit tests.

This can simply achieved by using the plain call:

mvn test

cause the integration tests phase is not run (see the build life cycle).

  1. If I run mvn integration-test, I want to compile and execute all tests.

This means running the default which includes running the test phase which will run the unit tests (maven-surefire-plugin) and furthermore running the integration test which are handled by the maven-failsafe-plugin. But you should be aware that if you like to call the integration tests you should using the following command:

mvn verify

instead, cause you missed the post-integration-test phase in your previous call.

Apart from the above you should follow the naming conventions for unit and integration tests where unit tests should be named like the following:

<includes>
 <include>**/*Test*.java</include>
 <include>**/*Test.java</include>
 <include>**/*TestCase.java</include>
</includes>

and integration tests should be named like the following:

<includes>
 <include>**/IT*.java</include>
 <include>**/*IT.java</include>
 <include>**/*ITCase.java</include>
</includes>

I hope you have configured the maven-failsafe-plugin like the following which is needed to bound the maven-failsafe-plugin to the correct life-cycle-phases:

<project>
  [...]
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-failsafe-plugin</artifactId>
        <version>2.15</version>
        <executions>
          <execution>
            <goals>
              <goal>integration-test</goal>
              <goal>verify</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  [...]
</project>

as you correctly did, but you should be aware that the include tags work on the source code (.java) and not on the compiled names (.class). I wouldn't use the Category annotation, just simply using the naming conventions makes the pom simpler and shorter.


According to the Failsafe Plugin documentation

mvn install -DskipITs

is what you want.


What OP stated in his question:

If I run mvn install, I want all tests to compile, but I do not want to execute any.
If I run mvn test, I want all tests to compile, but execute only unit tests.
If I run mvn integration-test, I want to compile and execute all tests.

is perfectly valid and extremely easy to achieve.
EDIT: except first condition, which acts againts the maven nature. The best way here would be simply do mvn install -DskipTests

All you need is following snippet in pom.xml:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.17</version>
    <executions>
        <execution>
            <id>integration-tests</id>
            <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
</plugin>

and to stick to the maven naming conventions for unit and integration tests (as @khmarbaise already stated). So generally name you integration tests with IT suffix (for example MyIntegrationTestIT.java) and let maven-failsafe do its job.
In that way, you do not even need JUnit categories (although sometimes they can be quite useful).

That's it :)

  • mvn test executes only unit tests
  • mvn integration-test executes all tests
  • mvn failsafe:integration-test runs only integration tests
  • mvn clean verify when you want to be sure, that whole project just works

Some personal advices

Keeping integration tests separately from unit tests lets you easily run within your IDE all tests in some package. Usually additional directory called test-integration (or integrationtest) is used for this purpose.
This is also easy to achieve with maven:

<plugin>
    <!-- adding second test source directory (just for integration tests) -->
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>1.9.1</version>
    <executions>
        <execution>
            <id>add-integration-test-source</id>
            <phase>generate-test-sources</phase>
            <goals>
                <goal>add-test-source</goal>
            </goals>
            <configuration>
                <sources>
                    <source>src/test-integration/java</source>
                </sources>
            </configuration>
        </execution>
    </executions>
</plugin>

And then move your integration tests to that directory. It should look like:

src
   main
   test
   test-integration

Integration tests usually needs more memory:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    ...
    <configuration>
        <argLine>-Xmx512m -XX:MaxPermSize=256m</argLine>
    </configuration>
</plugin>

This post explains how to skip integration tests, no matter what plugin you are using for these tests.

Basically, what you do is define a profile and put all your integration-tests related xml code inside that profile. Than you activate it when a property -DskipIntegrationTests is missing.

You can do the same for unit tests: write a profile and activate it when -DskipUnitTests is missing.

Then, you could do:

mvn install -DskipIntegrationTests -DskipUnitTests # (runs install without any tests)
mvn test # (runs unit tests)
mvn post-integration-test # (runs all tests)

The maven-failsafe-plugin docs has a section titled "Skipping by Default."

Sadly, the steps that page describes don't work as written. However, a slight change to those steps will make it work:

In the properties section of pom.xml, add this:

<skipITs>true</skipITs>

Then add the skipTests property to the plugin section of maven-failsafe-plugin:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <configuration>
        <skipTests>${skipITs}</skipTests>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
</plugin>

So now, an mvn install by default will execute unit tests, but not integration tests.

But an mvn install -DskipITs=false will execute both unit tests and integration tests.

Footnote: Bad documentation played a big part on why Maven was so disliked for such a long time.