I have a Spring Boot application build on Maven. I'm using Spring profiles to distinguish environment-specific configuration. I would like to prevent running tests when a specific Spring profile is active. Reason: I would like to prevent running tests with production properties (spring.profiles.active=prod). I would like to do this globally (maybe with some Maven plugin) instead of on each test separately.
Do you have any checked solutions for this?
<profiles>
<profile>
<id>prod</id>
<properties>
<maven.test.skip>true</maven.test.skip>
</properties>
</profile>
</profiles>
You can use #IfProfileValue annotation. But you have to add some values to your active profile and read it with mentioned annotation. You can read more here (section 3.4.3): https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#integration-testing
EDIT:
Another solution is to exclude all (or selected tests) tests in the Surefire plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>${exclude.tests}</exclude>
</excludes>
</configuration>
</plugin>
...
<profile>
<id>prod</id>
<properties>
<exclude.tests>**/*.*</exclude.tests>
</properties>
</profile>
And then when you run mvn clean test -Pprod all tests will be skipped
Related
Objectives
I'm adding integration tests to a Maven build. I want to achieve the following goals:
Only unit tests are run by default.
It must be possible to run only integration tests.
Current state
The task becomes more complicated because this is an existing application with a confusing structure (hierarchy) of maven modules. I'll try to explain.
So I have an aggregator pom (super pom) that looks like
<groupId>com.group.id</groupId>
<artifactId>app-name</artifactId>
<modules>
<module>SpringBootApp1</module>
<module>SpringBootApp2</module>
</modules>
<packaging>pom</packaging>
<profiles>
<profile>
<id>Local</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<!-- 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>
<profile>
<id>Test</id>
<properties>
<!-- Only integration tests are run when the test profile is active -->
<skip.integration.tests>false</skip.integration.tests>
<skip.unit.tests>true</skip.unit.tests>
</properties>
</profile>
</profiles>
and a few module poms that do not inherit from super pom (they inherit from spring-boot-starter-parent) and look like
<groupId>com.group.id</groupId>
<artifactId>spring-boot-app</artifactId>
<packaging>jar</packaging>
<name>Spring Boot app</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<build>
<finalName>SpringBootApp1</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.21.0</version>
<configuration>
<skipTests>${skip.unit.tests}</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.21.0</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>
<skipTests>${skip.integration.tests}</skipTests>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
As you see I define skip.integration.tests and skip.unit.tests properties in the aggregator pom (property values are different for different profiles) and try to use them in module poms.
Problem
When I execute mvn clean test -P Test or mvn clean verify -P Test to run tests I see that properties are not applied (e.g. unit tests are executed although skip.unit.tests is true).
I could declare aggregator pom as parent of module pom and maybe it would solve the problem, but module poms already have spring-boot-starter-parent declared as their parent.
Questions
Is it possible to use properties from aggregator pom without making it a parent?
How can I separate integration tests from unit tests by using properties in aggregator pom?
ps. I assure you that I adhere to naming conventions: unit tests are named like *Test.java and integration tests are named like *IT.java. So maven-failsafe-plugin and maven-surefire-plugin distinguish them.
If you can make your aggregator as a parent for your modules, and than configure aggregator to have spring-boot-starter-parent as parent this problem will be solved.(assuming your aggregator does not have any parent currently).
Or you can pass skip test property from command line like -Dskip.unit.tests=true(where you call your mvn clean verify).
As a side note, when you execute mvn test command you don't have to specify integration test to skip, because it is later in the lifecycle.(it won't be executed any way)
I have a JUnit 4.12 SlowTests test suite that I want to exclude from execution unless specifically requested on the Maven command line.
I have added the following to my pom file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<excludedGroups>com.Example.SlowTests</excludedGroups>
<includes>
<include>**/*TestSuite.class</include>
</includes>
<excludes>
<exclude></exclude>
</excludes>
</configuration>
</plugin>
I have defined the category as SlowTests and applied it to the MySlowTests class.
I have annotated the test suite as follows:
#RunWith(Categories.class)
#IncludeCategory(SlowTests.class)
#SuiteClasses({ MySlowTests.class })
public class MySlowTestSuite
When I run mvn package all the unit tests except MySlowTests are executed.
However, looking at various answers such as https://stackoverflow.com/a/25639372/820657 and https://stackoverflow.com/a/21830866/820657 I expected the following command:
mvn package -Dgroups=com.Example.MySlowTests
to run the excluded MySlowTests tests but they don't run. In fact no tests run.
What am I doing wrong?
The Maven Surefire plugin has some issues w.r.t categories in versions < 2.13 (IIRC) but as long as you are using Surefire >= 2.13 the following will run any classes annotated with #Category(com.yourcompany.SlowTests.class):
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.13</version>
<configuration>
<groups>com.yourcompany.SlowTests</groups>
</configuration>
</plugin>
This approach is often used with profiles, the following configuration ...
<profiles>
<profile>
<id>slow</id>
<properties>
<testCategories>com.yourcompany.SlowTests</testCategories>
</properties>
</profile>
<profile>
<id>fast</id>
<properties>
<testCategories>com.yourcompany.FastTests</testCategories>
</properties>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.13</version>
<configuration>
<groups>${testCategories}</groups>
</configuration>
</plugin>
</plugins>
</build>
... can be used to run:
mvn install -P slow: runs the slow tests only
mvn install -P fast: runs the fast tests only
mvn install -P fast,slow: runs the fast and slow tests
Update 1: for this question: "Is there a way to use this approach so I can run all fast tests by default?"
You can define two properties:
<properties>
<includedCategories></includedCategories>
<excludedCategories>com.yourcompany.SlowTests</excludedCategories>
</properties>
Then update your surefire plugin definition like so:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.13</version>
<configuration>
<groups>${includedCategories}</groups>
<excludedGroups>${excludedCategories}</excludedGroups>
</configuration>
</plugin>
And, finally, add this profile:
<profile>
<id>slow</id>
<properties>
<includedCategories>com.yourcompany.SlowTests</includedCategories>
<excludedCategories></excludedCategories>
</properties>
</profile>
This just toggles the includedCategories and excludedCategories properties. By default, you include everything except those tests annotated with com.yourcompany.SlowTests (i.e. everything except your 'slow' tests). When you run with -P slow you exclude everything except those tests annotated with com.yourcompany.SlowTests (i.e. everything except your 'slow' tests).
Note: what I said in my original answer about Surefire versions < 2.13 misbehaving with Categories still stands so to make this work you need to be using a version of the Maven Surefire plugin >= 2.13.
I'm trying to set an active profile in Spring Boot application using Maven 3.
In my pom.xml I set default active profile and property spring.profiles.active to development:
<profiles>
<profile>
<id>development</id>
<properties>
<spring.profiles.active>development</spring.profiles.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
but every time I run my application, I receive the following message in logs:
No active profile set, falling back to default profiles: default
and the SpringBoot profile is set to default (reads application.properties instead application-development.properties)
What else should I do to have my SpringBoot active profile set using Maven profile?
Any help highly appreciated.
The Maven profile and the Spring profile are two completely different things. Your pom.xml defines spring.profiles.active variable which is available in the build process, but not at runtime. That is why only the default profile is activated.
How to bind Maven profile with Spring?
You need to pass the build variable to your application so that it is available when it is started.
Define a placeholder in your application.properties:
spring.profiles.active=#spring.profiles.active#
The #spring.profiles.active# variable must match the declared property from the Maven profile.
Enable resource filtering in you pom.xml:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
…
</build>
When the build is executed, all files in the src/main/resources directory will be processed by Maven and the placeholder in your application.properties will be replaced with the variable you defined in your Maven profile.
For more details you can go to my post where I described this use case.
Or rather easily:
mvn spring-boot:run -Dspring-boot.run.profiles={profile_name}
There are multiple ways to set profiles for your springboot application.
You can add this in your property file:
spring.profiles.active=dev
Programmatic way:
SpringApplication.setAdditionalProfiles("dev");
Tests make it very easy to specify what profiles are active
#ActiveProfiles("dev")
In a Unix environment
export spring_profiles_active=dev
JVM System Parameter
-Dspring.profiles.active=dev
Example: Running a springboot jar file with profile.
java -jar -Dspring.profiles.active=dev application.jar
You can run using the following command. Here I want to run using spring profile local:
spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=local"
In development, activating a Spring Boot profile when a specific Maven profile is activate is straight. You should use the profiles property of the spring-boot-maven-plugin in the Maven profile such as :
<project>
<...>
<profiles>
<profile>
<id>development</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<profiles>
<profile>development</profile>
</profiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profiles>
</...>
</project>
You can run the following command to use both the Spring Boot and the Maven development profile :
mvn spring-boot:run -Pdevelopment
If you want to be able to map any Spring Boot profiles to a Maven profile with the same profile name, you could define a single Maven profile and enabling that as the presence of a Maven property is detected. This property would be the single thing that you need to specify as you run the mvn command.
The profile would look like :
<profile>
<id>spring-profile-active</id>
<activation>
<property>
<name>my.active.spring.profiles</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<profiles>
<profile>${my.active.spring.profiles}</profile>
</profiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
And you can run the following command to use both the Spring Boot and the Maven development profile :
mvn spring-boot:run -Dmy.active.spring.profiles=development
or :
mvn spring-boot:run -Dmy.active.spring.profiles=integration
or :
mvn spring-boot:run -Dmy.active.spring.profiles=production
And so for...
This kind of configuration makes sense as in the generic Maven profile you rely on the my.active.spring.profiles property that is passed to perform some tasks or value some things.
For example I use this way to configure a generic Maven profile that packages the application and build a docker image specific to the environment selected.
You should use the Spring Boot Maven Plugin:
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.1.RELEASE</version>
<configuration>
<profiles>
<profile>foo</profile>
<profile>bar</profile>
</profiles>
</configuration>
...
</plugin>
...
</plugins>
...
</build>
...
</project>
I would like to run an automation test in different environments.
So I add this to command maven command:
spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=productionEnv1"
Here is the link where I found the solution: [1]https://github.com/spring-projects/spring-boot/issues/1095
I wanted to clarify the excellent answer https://stackoverflow.com/a/42391322/13134499 from Daniel Olszewski if you want to use it just for tests.
How to bind Maven profile with Spring for tests?
As you did, define the variable in pom.xml
...
<properties>
<spring.profiles.active>development</spring.profiles.active>
</properties>
Define a placeholder in your application-test.properties in src/test/resources:
spring.profiles.active=#spring.profiles.active#
Enable resource filtering in you pom.xml:
<build>
...
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</testResource>
<testResources>
</build>
file structure:
/src/main/resources
=>
application.properties:
spring.profiles.active:#spring.profiles.active#'
application-dev.properties
application-prod.properties
IDE-Eclipse:
Right click on the project=>Run As=>Run Configuration=>Arguments=>VM Arguments:-Dspring.profiles.active=dev
CMD:
mvn spring-boot:run -Dspring.profiles.active=dev
mvn clean install -Dspring.profiles.active=dev
I would like to mention I am relatively new in Maven configurations.
My situation:
I use Maven 3.0.5 to build J2E application
the application is deployed in four different environments: local, dev, test and prod
I use maven profiles to configure environment-specific configurations
I have defined these configurations in properties files in the file system.
This is the file system for those:
<my-project-root>
---profiles
------local
---------app.properties
------dev
---------app.properties
------test
---------app.properties
I load the corresponding property file with the following logic in my pom.xml:
<profiles>
<profile>
<id>local</id>
<!-- The development profile is active by default -->
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<build.profile.id>local</build.profile.id>
</properties>
</profile>
<profile>
<id>dev</id>
<properties>
<build.profile.id>dev</build.profile.id>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<build.profile.id>prod</build.profile.id>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<build.profile.id>test</build.profile.id>
</properties>
</profile>
</profiles>
<build>
<finalName>MyProject</finalName>
<plugins>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>profiles/${build.profile.id}</directory>
</resource>
</resources>
</build>
With this configuration I can use the respective properties for my current profile almost everywhere. Everywhere, but the <plugins> section. I would pretty much like to load e.g, my database url or credentials from such properties files, but if I include them in the app.properties they are not evaluated in the plugins section (e.g. I get value of ${endpoint} as database endpoint).
How do I get the properties loaded from files for the profile accessible in the <plugins> section?
PS: Yes, if I add those properties directly in the pom.xml as properties under <profiles> tag, they are accessible, but I would rather keep my passwords off the pom.
I was able to do what I wanted to do. I used properties-maven-plugin linked from, say this answer.
What I did was the following:
I added the properties-maven-plugin to read the files I needed loaded
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>profiles/${build.profile.id}/app.properties</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
Regretfully, here I was not able to make the plugin read all property files in a directory, but I find this good enough.
I also needed to remove the error the plugin definition above gave for me in Eclipse (Plugin execution not covered by lifecycle configuration). To do thatI followed the instructions from the following post.
With those steps the properties I needed became available for the plugins, that used them.
Note: actually the properties get loaded after the compile maven command, but this is good enough for me, as all my property-dependant goals are to be executed after compile goal in sequence of goal calls in all my cases.
We've had an ongoing need here that I can't figure out how to address using the stock Maven 2 tools and documentation.
Some of our developers have some very long running JUnit tests (usually stress tests) that under no circumstances should be run as a regular part of the build process / nightly build.
Of course we can use the surefire plugin's exclusion mechanism and just punt them from the build, but ideally we'd love something that would allow the developer to run them at will through Maven 2.
Normally you would add a profile to your maven configuration that runs a different set of tests:
run this with mvn -Pintegrationtest install
<profile>
<id>integrationtest</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-client -Xmx896m -XX:MaxPermSize=192m</argLine>
<forkMode>once</forkMode>
<includes>
<include>**/**/*Test.java</include>
<include>**/**/*IntTest.java</include>
</includes>
<excludes>
<exclude>**/**/*SeleniumTest.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<activation>
<property>
<name>integrationtest</name>
</property>
</activation>
</profile>
Adding to krosenvold's answer, to ensure no unexpected behavior, make sure you also have a default profile that is active by default that excludes the integration or stresstests you want to run in your special profile.
<profile>
<id>normal</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/**/*IntTest.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
You will need to create a profile like this, simply listing the surefire-plugin outside of a profile will override the profile should it be selected with:
mvn -P integrationtest clean install
Use an integration test plugin such as the Super Helpful Integration Test Thingy to separate Integration Tests (long running, systemic) from Unit Test (purists say 30 seconds max for all true unit tests to run). Make two Java packages for your unit tests versus integration tests.
Then do not bind this plugin to a phase (the normal maven lifecycle) and only run it when it is explicitly called as a target, like so:
mvn shitty:clean shitty:install shitty:test
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>shitty-maven-plugin</artifactId>
</plugin>
</plugins>
This way, your normal developers will not be impacted, and you'll be able to run integration tests on demand.
Another option is to have the stress test detect it is running in maven and run only once or twice. i.e. turn into a regular functional test. This way you can check the code is still good, but not run for a long time.