Stacking properties by specifying multiple Maven profiles on the command line - java

I finally got my test automation running using JUnit4 #Category for each test; they are marked as either PriorityHigh, PriorityMedium, or PriorityLow.
In my pom.xml I have each set up as a profile:
<profile>
<id>PriorityHigh</id>
<properties>
<testcase.category>com.categories.PriorityHigh</testcase.category>
</properties>
</profile>
<profile>
<id>PriorityMedium</id>
<properties>
<testcase.category>com.categories.PriorityMedium</testcase.category>
</properties>
</profile>
<profile>
<id>PriorityLow</id>
<properties>
<testcase.category>com.categories.PriorityLow</testcase.category>
</properties>
</profile>
Which is then used in the plugin section:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire.version}</version>
<configuration>
<groups>${testcase.category}</groups>
<systemPropertyVariables>
<automation.driver>${browser.name}</automation.driver>
</systemPropertyVariables>
</configuration>
</plugin>
My issue is when I want to test both Medium and High, I specify
-P PriorityHigh,PriorityMedium
But instead of adding/concatenating, they overwrite and so only Medium tests run. To add extra difficulty, since pom.xml complains that ${testcase.category} only exists in profiles, and no default, I had to add this:
<testcase.category>com.categories.PriorityHigh,com.categories.PriorityMedium,com.categories.PriorityLow</testcase.category>
in case no profile is specified.
So two questions:
How to get the profiles to stack correctly in the "groups" node?
A better way to work it if no profile is specified (all tests should run)?

The easiest thing to do would be to ditch profiles and just use system properties:
<properties>
<testcase.category>com.categories.PriorityHigh,com.categories.PriorityLow</testcase.category>
</properties>
...
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<groups>${testcase.category}</groups>
...
</configuration>
</plugin>
Then:
mvn verify -Dtestcase.category=com.categories.PriorityHigh
# runs PriorityHigh tests
mvn verify -Dtestcase.category=com.categories.PriorityHigh,com.categories.PriorityLow
# runs PriorityHigh and PriorityLow tests
mvn verify
# runs PriorityHigh and PriorityLow tests
If you don't want to have to specify the fully qualified category class name on the Maven command line, you could use the Build Helper plugin to qualify the names for you:
<properties>
<testcase.category>PriorityHigh,PriorityLow</testcase.category>
</properties>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>build-fq-testcase-category</id>
<goals>
<goal>regex-property</goal>
</goals>
<configuration>
<name>fq.testcase.category</name>
<regex>([^,]+)</regex>
<value>${testcase.category}</value>
<replacement>com.categories.$1</replacement>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<groups>${fq.testcase.category}</groups>
</configuration>
</plugin>
Then:
mvn verify -Dtestcase.category=PriorityHigh
# just run PriorityHigh tests
mvn verify
# run PriorityLow and PriorityHigh tests
# etc.

Related

How to skip integration tests by default but still run them on-demand in multi-module maven project?

I have a multi module project having the following structure:
Project:
- module1
- module2
- integration-test
- parent pom
What is the correct way of achieving the following:
run unit tests from all modules(except integration-test) using mvn clean install
run integration tests on demand(may be by using maven-failsafe plugin or via a maven profile? )
fail the build when integration tests fail.
By Default integration tests should not be run using mvn clean install
integration-test module has only the integration tests.
I have tried multiple hacks using maven-failsafe plugin and maven-sunfire-plugin(for unit tests) but not able to achieve the above in standard way.
Following is how the relevant portion of integration-test pom looks like:
<dependencies>
<!-- dependencies required for this module-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.12</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/test/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/test/resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>run-its</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
currently when i run mvn clean install it runs integration tests too. When i run mvn -Prun-its clean verify, it is running unit tests from other modules too. what am i missing?
You can skip execution of the Integration tests simply by setting -DskipITs=true when running your build like so:
mvn clean install -DskipITs=true
this will run all other tests but your ITs (see here for doc).
If you only want to run
mvn clean install
you can set the default for skipITs in your pom.xml
<properties>
<skipITs>true</skipITs>
</properties>
This way you can override it on demand with
mvn clean install -DskipITs=false
To run only ITs without Unittests you can configure the -Property of the maven-surefire-plugin like so
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skip>${skipUnitTests}</skip>
</configuration>
</plugin>
so if you run
mvn clean install -DskipITs=false -DskipUnitTests=true
Note that skipUnitTests will be false by default so no need to declare a property for that.
If you'd rather use a Profile it should work like that
<profile>
<id>ITs</id>
<properties>
<skipUnitTests>true</skipUnitTests>
<skipITs>false</skipITs>
</properties>
</profile>
and run the build like so
mvn clean install -PITs
Of course you could also use the plugin-configuration for maven-surefire-plugin with true directly in the profile so there'd be no need for the extra property, like
<profile>
<id>ITs</id>
<properties>
<skipITs>false</skipITs>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</profile>
I don't know if that's the best solution but you can achieve that using profiles. For example in the main pom.xml you add just the other modules in the <modules> section and then add another profile:
<modules>
... standard modules ...
</modules>
<profiles>
<profile>
<id>tests</id>
<modules>
<module>module1</module>
... standard modules repeated (it might not be needed>...
<module>module2</module>
<module>module-integration-test</module>
</modules>
</profile>
</profiles>
Then you run maven with that profile if you wnat to run tests.
maven -P tests clean install
That would work if you want to run integration tests AND the other modules. If you want to run just the integration tests you can do it like that:
<modules>
<!-- EMPTY -->
</modules>
<profiles>
<profile>
<id>defaultModule</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<modules>
<module>module1</module>
... standard modules repeated (it might not be needed>...
<module>module2</module>
</modules>
</profile>
<profile>
<id>tests</id>
<modules>
<module>module-integration-test</module>
</modules>
</profile>
</profiles>
This way with mvn clean install you will run with defaultModule (which is activeByDefault) and if you specify -P tests you will run just tests
The best is to make a separate module which contains the integration tests which looks like already shown in your own question. Now how to handle the integration tests being running or not ...
The integration-test module looks like this:
<?xml version="1.0"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>groupOfYourParant</groupId>
<artifactId>integration-test</artifactId>
<version>0.1.0-SNAPSHOT</version>
</parent>
<artifactId>integration-test</artifactId>
<packaging>jar</packaging>
<name>Mod-IT</name>
<dependencies>
<dependency>
<groupId>groupId</groupId>
<artifactId>TheArtifact</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Supplemental deps only needed in this module -->
<dependency>
<groupId>....</groupId>
<artifactId>....</artifactId>
<version>...</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>run-its</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
By using this you can simply control to run the integration tests via:
mvn -Prun-its clean verify
It's important that you have define the dependencies to other modules which are needed by the integration tests module or where it made be sure that those modules have to be built before this integration test module.
Furthermore you can now configure here supplemental things which are needed for integration tests and which should be run for example in the pre-integration-test and/or in post-integration-test phase.
If you put the test code into src/test/java plus optional resources into src/test/resources you can now define dependencies within your integration test module separately from any other module.
You should of course define the versions for your plugins in a pluginManagement in your parent pom to define all plugins which are being used during a build.

How can I exclude files of the Code Coverage of SonarQube using JaCoCo maven plugin

I've got a big issue with the integration of JaCoCo maven plugin for the code covering of SonarQube 6.0.
I've got a multi-module Maven project lets say :
master
|--core
|--web
|--process
in the master pom.xml, I've setted a reporting profile like that :
<profile>
<id>reporting</id>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>pre-unit-test</id>
<!--<phase>test</phase> -->
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<!-- Sets the path to the file to write the execution data to. -->
<destFile>${sonar.jacoco.reportPath}</destFile>
<!-- Connection with SureFire plugin -->
<propertyName>sonarUnitTestArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<!-- Sets the path to where the execution data is located. -->
<dataFile>${sonar.jacoco.reportPath}</dataFile>
<!-- Sets the output directory for the code coverage report. -->
<outputDirectory>${jacoco.ut.outputdir}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkMode>once</forkMode>
<argLine>${sonarUnitTestArgLine} -XX:MaxPermSize=512M -Xms512m -Xmx512m</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
in the childs, I overload the configuration by adding some exclusions :
<!-- First attempt -->
<properties>
<sonar.jacoco.excludes>**/model/**/*</sonar.jacoco.excludes>
</properties>
<!-- Second attempt -->
<properties>
<sonar.coverage.exclusions>**/model/**/*</sonar.coverage.exclusions>
</properties>
<!-- Third attempt -->
<profiles>
<profile>
<id>reporting</id>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<excludes>
<!-- Exclude model classes (POJO's) -->
<exclude>**/model/**/*.class</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
the idea here is to remove the Pojo of the code coverage ( we also do it for other types of Class ...)
When I run the mvn command line :
mvn clean generate-sources install verify -P reporting -fn
All my reports are well generated but in Sonar, the exculsions aren't been taking into account ...
Please can you help me fixing this issue ?
After a lot of reasearch, I've found the solution for this problem, I post the answers to help poeple ho'll have the same issue :
In the master-module
<properties>
<sonar.coverage.exclusions>
**/patternA/**/*,
**/patternB/**/*
</sonar.coverage.exclusions>
</properties>
In the sub-modules
<profiles>
<profile>
<id>report</id>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<excludes>
<!-- Exclude model classes (POJO's) -->
<exclude>**/patternA/**/*.class</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
in the master pom
I tried adding just the below details in properties section and it worked for me.
<sonar.coverage.exclusions>
**/patternA/*.java,
**/patternB/*.java
</sonar.coverage.exclusions>

Maven profile and artifact version

Assume we have maven multimodule project "Foo":
Foo
|-web-module-war
|-dependency-jar
There are two profiles defined for moduleC:
<profile>
<id>poll-some-external-service</id>
<properties>
<dependency-jar.poll.configured>true</dependency-jar.poll.configured>
</properties>
</profile>
<profile>
<id>produce-some-product</id>
<properties>
<dependency-jar.poll.configured>false</dependency-jar.poll.configured>
</properties>
</profile>
Now we run two builds:
mvn clean package -P poll-some-external-service
mvn clean package -P produce-some-product
First build produce following artifacts:
web-module-war-1.0.0-poll.war
dependency-jar-1.0.0-poll.war
Second build produce following artifacts:
web-module-war-1.0.0-produce.war
dependency-jar-1.0.0-produce.war
This means that war file contains web application which works in a different way based on selected profile.
Naming is based on the following configuration in the parent pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<jarName>${project.build.finalName}${foo.build.info}</jarName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<warName>${project.build.finalName}${foo.build.info}</warName>
</configuration>
</plugin>
How can I deploy these artifacts into Nexus? -poll/-produce part is stripped during deployment. This means we have two different applications of the same version but we can deploy only one of them
Thanks
Instead of changing the name use a classifier
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<classifier>poll</classifier>
</configuration>
</plugin>
Your profile for the pom should look similar to the following example. Note that you have to change the dependencies by using the profile too.
<profile>
<id>poll</id>
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<classifier>poll</classifier>
</configuration>
</plugin>
</plugins>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>dependency-jar</artifactId>
<classifier>poll</classifier>
</dependency>
</dependencies>
</build>
</profile>

How can I fire integration tests separately using failsafe-plugin?

I cannot run integration tests, but only unit tests.
Here is my Maven config (see code below). It uses two plugins. One of them is maven-failsafe-plugin and the second one is maven-surefire-plugin.
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<skipTests>false</skipTests>
<skipITs>${skipTests}</skipITs>
<skipUTs>${skipTests}</skipUTs>
</properties>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<skipTests>${skipUTs}</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.16</version>
<configuration>
<skipTests>${skipTests}</skipTests>
<skipITs>${skipITs}</skipITs>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
I try to run unit tests using this commend
mvn clean test
And there is the command to start integration tests separately
mvn clean failsafe:integration-test verify
Result of invocation of the last command is
[INFO] --- maven-failsafe-plugin:2.16:integration-test (default-cli) # integration-test-demo ---
[INFO] No tests to run.
I use profiles for these:
Properties
<properties>
<!-- Only unit tests are run by default. -->
<skip.integration.tests>true</skip.integration.tests>
<skip.unit.tests>false</skip.unit.tests>
</properties>
Profiles
<profiles>
<profile>
<id>all-tests</id>
<properties>
<build.profile.id>all-tests</build.profile.id>
<!-- All tests are run. -->
<skip.integration.tests>false</skip.integration.tests>
<skip.unit.tests>false</skip.unit.tests>
</properties>
</profile>
<profile>
<id>dev</id>
</profile>
<profile>
<id>integration-tests</id>
<properties>
<!-- Used to locate the profile specific configuration file. -->
<build.profile.id>integration-test</build.profile.id>
<!-- Only integration tests are run. -->
<skip.integration.tests>false</skip.integration.tests>
<skip.unit.tests>true</skip.unit.tests>
</properties>
</profile>
</profiles>
maven-surefire-plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.15</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>**/*IntegrationTest.java</exclude>
</excludes>
</configuration>
</plugin>
maven-failsafe-plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.15</version>
<executions>
<!-- Ensures that both integration-test and verify goals of the Failsafe Maven plugin are executed. -->
<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>
<includes>
<include>**/*IntegrationTest.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
The Integration Tests end in ...IntegrationTest.java, and I run the profile that I required (all-tests, integration-tests). The unit tests are run by default.
I am pretty sure that I copied this from somewhere, but now I can not remember the link. Sorry.

How do I set in the pom to not compile tests?

How do I set in the pom to not compile tests in Maven? I've tried:
<properties>
<skipTests>true</skipTests>
</properties>
but in that case, Maven compile the tests but don't run them. I need Maven don't compile my tests.
You have to define maven.test.skip to true.
<properties>
<maven.test.skip>true</maven.test.skip>
</properties>
http://maven.apache.org/surefire/maven-surefire-plugin/examples/skipping-test.html
In my case a solution was to put tests in a profile (e.g. runTests), so when I want to run these tests, I add the parameter -PrunTests. Thanks for the replies.
Configure maven-compiler-plugin to skip the compilation.
Once again, I do not recommend it.
<project>
<properties>
<maven.test.skip>true</maven.test.skip>
</properties>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<executions>
<execution>
<id>default-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<skip>${maven.test.skip}</skip>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>
If you are using the surefire-plugin for executing tests, you can configure it to skip them based on a naming pattern:
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.14</version>
<configuration>
<includes>
<include>%regex[.*[Cat|Dog].*Test.*]</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
[...]
</project>
This, however, requires the tests file names to conform to the desired pattern(s). At work we are using this approach, and have our tests end with ..UnitTest or ..IntegrationTest, so that we can easily turn each of them off by modifying the regex in the corresponding build profile.
Take a look at Apache's documentation on the surefire plugin. You may find something more useful or better suited for your case.

Categories