I have these properties in my application.properties:
spring.datasource.url=jdbc:postgresql://localhsost:5432/myDatabase
spring.datasource.username=myUsername
I would like to run mvn test with other values than the above, for example:
spring.datasource.url=jdbc:postgresql://my.test.server.com:5432/myDatabase
spring.datasource.username=anotherUsername
I tried the following
mvn test -Drun.arguments='--spring.datasource.jdbc:postgresql://my.test.server.com:5432/myDatabase --spring.datasource.username=anotherUsername'
and without spring prefix:
mvn test -Drun.arguments='--datasource.jdbc:postgresql://my.test.server.com:5432/myDatabase --datasource.username=anotherUsername'
But this does not seem to work. How can I override the values in the application.properties in context of running mvn test?
Something like this should work:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
<configuration>
<systemPropertyVariables>
<spring.datasource.jdbc>value</spring.datasource.jdbc>
</systemPropertyVariables>
</configuration>
</plugin>
But more often we do this by placing a test version of application.properties into the src/test/resources. During testing, that file will have greater priority.
When overriding parameters in the command line, use a comma as separator, not a space:
mvn test -Drun.arguments='--spring.datasource.url=...,--spring.datasource.username=...'
This should work too:
mvn test -Dspring.datasource.url=... -Dspring.datasource.username=...
Edit from april 2021
The syntax above was valid for Spring Boot 1.X.
With Spring Boot 2.0/2.1, use:
mvn test -Dspring-boot.run.arguments='--spring.datasource.url=...,--spring.datasource.username=...'
And with Spring Boot 2.2, the syntax was changed again (use a whitespace as separator):
mvn test -Dspring-boot.run.arguments='--spring.datasource.url=... --spring.datasource.username=...'
Other answers and comments mention using profiles and put a custom application.properties in /src/test/resources, which is not a viable solution for you since you use different pipelines, but if I remember correctly, you can even use application-{profile}.properties in /src/test/resources. This way you should be able to maintain one test profile per pipeline, where you put your custom parameters, and then test your pipeline with:
mvn test -Dspring.profiles.active=foobar
Option 1 (preferred as is Maven structure-specific)
Create an application.properties under the test/resources to be picked up for your testing purposes
Option 2 (Spring Test fine-tuning a particular Test class alone)
Override your properties directly on the Test class by inlining the ones you want by using #TestPropertySource
Option 3 (Spring Boot - multiple properties files or a single YAML file)
Group the props under a Spring Profile (Example here) and invoke it directly from maven: mvn test -Dspring.profiles.active="myOtherSpringProfile"
Create another application-dev.properties file and paste:
spring.datasource.url=jdbc:postgresql://my.test.server.com:5432/myDatabase
spring.datasource.username=anotherUsername
Then run with the option -Dspring.profiles.active=dev in your mvn command.
E.g.: mvn test -Dspring.profiles.active=dev
You can add as many profiles as needed.
syntax: application-<profile name>.properties
I don't see many people using the environment variable option. If you set an environment variable for corresponding properties, then the value in the environment variable will be used. e.g.
Environment variables:
SPRING_DATASOURCE_URL="jdbc:postgresql://my.test.server.com:5432/myDatabase"
SPRING_DATASOURCE_USERNAME=anotherUsername
Inside the properties file:
spring.datasource.url=jdbc:postgresql://localhsost:5432/myDatabase
spring.datasource.username=myUsername
The application will use the values in the environment variables. For this to work you'll need to follow the naming convention. Use uppercase and replace "." with "_".
Related
I am looking for a solution to automatically add the environment variable SPRING_PROFILES_ACTIVE="test" when running unit-tests. The solution should fulfill the following criteria :
Ideally it should be configured via maven pom.xml
If 1 is not possible configuration should be done for IntelliJ via configuration file in the project not via UI setting
The particular environment variable should only be set when running unit tests not when generally launching the app.
Any idea on how to approach this goal is appreciated.
Best
Andy
The SPRING_PROFILES_ACTIVE is a property value that should be set in a file like application-test.properties or application-test.yml
In a yml file it would look like,
spring:
profiles:
active: test
Additionally, there are specific annotations to help identify certain classes/methods as test specific such as #Profile("test") or #ActiveProfiles("test").
I have edited, for example, application.properties from
spring.mail.host=stmp.test.com
to
spring.mail.host=${server.mail.host}
and I override at starttime these properties to the correct values. This works fine until I want to run maven to build my application.
I receive the following Exception
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class
I think the problem is that maven also needs these values but how and where can I insert them? I dont want to run mvn on the cli.
I think #Nicholas K was making the point that you can pass in those values in you maven command. For example with the argument mvn spring-boot:run "-Dserver.mail.host=mailhost".
You can also set an environment variable and that should be injected:
export SERVER_MAIL_HOST=mailhost
Or if you sometimes don't want to set them you could set a default for the property in your properties file:
spring.mail.host=${server.mail.host:defaultmailhost}
Or default it to an empty string
Is there any way to input arguments when launching spring-boot application (mvn spring-boot:run) from commandline and then get them in main()?
Looking at the source code of the spring-boot-maven-plugin I found that you need to do:
mvn spring-boot:run -Drun.arguments="arg1,arg2"
Another way to get more information about what options the run goal of the spring-boot plugin supports is to execute the following command:
mvn help:describe -Dcmd=spring-boot:run -Ddetail
For Spring Boot 2.x, the source is here and you now need to use -Dspring-boot.run.arguments="args1,args2"
(edit from april 2021)
For Spring Boot 2.2+, you now need to use -Dspring-boot.run.arguments="args1 args2"
If you are using Gradle and you want to be able to pass command line arguments to the Gradle bootRun task, you first need to configure, for example like so:
bootRun {
if ( project.hasProperty('args') ) {
args project.args.split('\\s+')
}
}
and run the task using gradle bootRun -Pargs="arg1 arg2"
When passing multiple arguments using -Drun.arguments, if the argument in turn has 'comma-separated' values, then only the first value of each argument is used. To avoid this repeat the argument as many times as the number of values.
This is more of a workaround. Not sure if there is an alternative unless the delimiter is different - like '|'.
E.g Issue:
mvn spring-boot:run -Drun.arguments="--spring.profiles.active=test,dev"
Picks only 'test' profile for the above command.
Workaround:
mvn spring-boot:run -Drun.arguments="--spring.profiles.active=test,--spring.profiles.active=dev"
Picks both 'dev' & 'test' profiles for the above command.
Be aware : The way of passing arguments depends on the spring-boot major.minor version.
TLDR
For Spring Boot 1:
mvn spring-boot:run -Drun.arguments="argOne,argTwo"
For Spring Boot 2.0 and 2.1:
mvn spring-boot:run -Dspring-boot.run.arguments="argOne,argTwo"
(edit from april 2021)
For Spring boot 2.2 and later:
mvn spring-boot:run -Dspring-boot.run.arguments="argOne argTwo"
spring-boot-maven-plugin version and the the Spring Boot version you use has to be aligned.
According to the Spring Boot major version used (1 or 2), the spring-boot-maven-plugin in the 1 or the 2 version should indeed be used.
If your pom.xml inherits from the spring-boot-starter-parent :
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>ONE_OR_TWO_VERSION</version>
</parent>
In your pom, the version of the plugin used should not even be specified as this plugin dependency is inherited :
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
...
</configuration>
</plugin>
</plugins>
In case of your pom.xml not inheriting from spring-boot-starter-parent, don't forget to align the version of spring-boot-maven-plugin with the exact version of spring boot you want to use.
Passing arguments in command line with spring-boot-maven-plugin:1.X.X
For one argument :
mvn spring-boot:run -Drun.arguments="argOne"
for multiple :
mvn spring-boot:run -Drun.arguments="argOne,argTwo"
The maven plugin page documents it :
Name Type Since Description
arguments | String[] | 1.0 | Arguments that should be passed
to the application. On command line use
commas to separate multiple arguments.
User property is: run.arguments.
Passing arguments in command line with spring-boot-maven-plugin:2.X.X
For one argument :
mvn spring-boot:run -Dspring-boot.run.arguments="argOne"
for multiple :
mvn spring-boot:run -Dspring-boot.run.arguments="argOne,argTwo"
I didn't find the plugin documentation for the 2.X.X version that refers to that.
But the org.springframework.boot.maven.AbstractRunMojo class of the spring-boot-maven-plugin:2.0.0.M3 plugin refers to this user property:
public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo
...
#Parameter(property="spring-boot.run.arguments")
private String[] arguments;
...
protected RunArguments resolveApplicationArguments(){
RunArguments runArguments = new RunArguments(this.arguments);
addActiveProfileArgument(runArguments);
return runArguments;
}
...
}
Hint : as you pass more than one argument, whitespaces between commas are considered.
mvn spring-boot:run -Dspring-boot.run.arguments="argOne,argTwo"
will be interpreted as ["argOne", "argTwo"]
But this :
mvn spring-boot:run -Dspring-boot.run.arguments="argOne, argTwo"
will be interpreted as ["argOne", " argTwo"]
(edit from march 2021)
Whitespaces are now used as separator for multiple-arguments commands, see the relevant issue.
As I checked today, the correct usage for Spring Boot 2.2.5 is:
mvn spring-boot:run -Dspring-boot.run.arguments="--arg1=value --arg2=value"
Because help says:
commandlineArguments
User property: spring-boot.run.arguments
Arguments from the command line that should be passed to the application.
Use spaces to separate multiple arguments and make sure to wrap multiple
values between quotes. When specified, takes precedence over arguments.
Spring Boot 1 as 2 provide a way to pass multiple profiles as argument and avoid the issue related to the comma used both as separator between the args and the values passed as active profile.
So instead of writing :
mvn spring-boot:run -Dspring-boot.run.arguments=--spring.profiles.active=test,--spring.profiles.active=dev
use the Spring Boot Maven profiles property that is a convenience shortcut of spring.profiles.active such as the followings :
The Maven user property is different according to the Spring Boot version.
For Spring Boot 1.4+, that is run.profiles :
mvn spring-boot:run -Drun.profiles=dev,test
For Spring Boot 2, that is spring-boot.run.profiles :
mvn spring-boot:run -Dspring-boot.run.profiles=dev,test
From the plugin documentation :
profiles:
The spring profiles to activate. Convenience shortcut of specifying
the 'spring.profiles.active' argument. On command line use commas to
separate multiple profiles.
Type: java.lang.String[]
Since: 1.3
Required: No
User Property: spring-boot.run.profiles
I'm using spring.boot 2.4.2 and i separated the arguments with withe-space and put the values between double quotes.
mvn spring-boot:run -Dspring-boot.run.arguments="--param1=value2 --param2=value2"
And if you're using Eclipse...
| Parameter Name | Value |
| run.arguments | "--name=Adam" |
This is what worked for me (spring-boot v1.4.3.RELEASE),.
mvn spring-boot:run -Dspring.profiles.active=test,local -Dlogback-debug=true
For the latest version of spring use -Dspring-boot.run.arguments= as shown in the example below
spring-boot:run -Djasypt.encryptor.password=temp -Dspring-boot.run.arguments="OU,Grade"
Use the following command for a Spring Boot application.
mvn spring-boot:run -Dspring-boot.run.arguments="--java.net.preferIPv4Stack=true --config.password=PASSWORD --config.token=s.TOKEN --spring.application.name=ENV --config.server.ip=IP_ADDRESS --spring.profiles.active=ENV --spring.profiles.active.custom=ENV_custom"
In our Spring web applications, we use the Spring bean profiles to differentiate three scenarios: development, integration, and production. We use them to connect to different databases or set other constants.
Using Spring bean profiles works very well for the changing the web app environment.
The problem we have is when our integration test code needs change for the environment. In these cases, the integration test loads the application context of the web app. This way we don't have to redefine database connections, constants, etc. (applying the DRY principle).
We setup our integration tests like the following.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = ["classpath:applicationContext.xml"])
public class MyTestIT
{
#Autowired
#Qualifier("myRemoteURL") // a value from the web-app's applicationContext.xml
private String remoteURL;
...
}
I can make it run locally using #ActiveProfiles, but this is hard-coded and causes our tests to fail on the build server.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = ["classpath:applicationContext.xml"])
#ActiveProfiles("development")
public class MyTestIT
{ ... }
I also tried using the #WebAppConfiguration hoping that it might somehow import the spring.profiles.active property from Maven, but that does not work.
One other note, we also need to configure our code so that developers can run the web app and then run the tests using IntelliJ's test runner (or another IDE). This is much easier for debugging integration tests.
As other people have already pointed out, you can opt to use Maven to set the spring.profiles.active system property, making sure not to use #ActiveProfiles, but that's not convenient for tests run within the IDE.
For a programmatic means to set the active profiles, you have a few options.
Spring 3.1: write a custom ContextLoader that prepares the context by setting active profiles in the context's Environment.
Spring 3.2: a custom ContextLoader remains an option, but a better choice is to implement an ApplicationContextInitializer and configure it via the initializers attribute of #ContextConfiguration. Your custom initializer can configure the Environment by programmatically setting the active profiles.
Spring 4.0: the aforementioned options still exist; however, as of Spring Framework 4.0 there is a new dedicated ActiveProfilesResolver API exactly for this purpose: to programmatically determine the set of active profiles to use in a test. An ActiveProfilesResolver can be registered via the resolver attribute of #ActiveProfiles.
Regards,
Sam (author of the Spring TestContext Framework)
I had a similar problem: I wanted to run all of my integration tests with a default profile, but allow a user to override with a profile that represented a different environment or even db flavor without having to change the #ActiveProfiles value. This is doable if you are using Spring 4.1+ with a custom ActiveProfilesResolver.
This example resolver looks for a System Property, spring.profiles.active, and if it does not exist it will delegate to the default resolver which simply uses the #ActiveProfiles annotation.
public class SystemPropertyActiveProfileResolver implements ActiveProfilesResolver {
private final DefaultActiveProfilesResolver defaultActiveProfilesResolver = new DefaultActiveProfilesResolver();
#Override
public String[] resolve(Class<?> testClass) {
if(System.getProperties().containsKey("spring.profiles.active")) {
final String profiles = System.getProperty("spring.profiles.active");
return profiles.split("\\s*,\\s*");
} else {
return defaultActiveProfilesResolver.resolve(testClass);
}
}
}
And in your test classes, you would use it like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles( profiles={"h2","xyz"},
resolver=SystemPropertyActiveProfileResolver.class)
public class MyTest { }
You can of course use other methods besides checking for the existence of a System Property to set the active profiles. Hope this helps somebody.
If you want to avoid hard-coding the profile you may want to use the system property spring.profiles.active and set it to whatever you need in that particular environment e.g. we have "dev", "stage" and "prod" profiles for our different environments; also we have a "test", "test-local" and "test-server" profiles for our testing.
Remember that you can have more than one profile in that system property by using a list of comma-separated values e.g. "test,test-qa".
You can specify system properties in a maven project in the maven surefire plugin or passing them like this:
mvn -DargLine="-DpropertyName=propertyValue"
As #ElderMael mentioned you could use the argLine property of maven surefire plugin. Often when I need to run all the test with different specific Spring profiles I define additional maven profile. Example:
<profiles>
<profile>
<id>foo</id>
<dependencies>
<!-- additional dependencies if needed, i.e. database drivers ->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Dspring.profiles.active=foo</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
With that approach you could easily run all the test with activated profile by maven command:
mvn clean test -Pfoo
The #ActiveProfile annotation is good but sometimes we need to run all the test with activated specific profiles and with hard-coded #ActiveProfile parameters it is a problem.
For example: by default integration test with H2 in-memory db, but sometimes you want to run test on the "real" database. You could define that additional maven profile and define Jenkins job. With SpringBoot you could also put additional properties to test/resources with name application-foo.yml (or properties) and those properties will be taken into account to.
there are many faces to this problem.
in my case, a simple addition to build.gradle already helped:
test { systemProperties = System.properties }
I'm in the need to run integration tests one by one with the failsafe plugin (please, don't ask why... They just have to run in individual jvms, one good reason for avoiding singletons).
So I'd like to create a script with one maven call per line where each maven call runs tests on a single test file. Something like this:
mvn failsafe:integration-test -D<???>=**/ITest1.java
mvn failsafe:integration-test -D<???>=**/ITest2.java
mvn failsafe:integration-test -D<???>=**/ITest3.java
...
In a pom.xml I'd add something like
<includes>
<include>**/ITest1.java</include>
</includes>
to the plugins configuration. Is there a way to achieve the same with the command line? Is it possible to specify list-like configuration options?
The syntax is:
mvn -Dit.test=TestName verify
Source: Failsafe Plugin Examples: Running a Single Test
The it.test parameter does that. You can read about it here.
From the docs:
[...] so you can just type "-Dit.test=MyTest" to run a single test called "foo/MyTest.java".