How to set environment variable or system property in spring tests?
You can initialize the System property in a static initializer:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
public class TestWarSpringContext {
static {
System.setProperty("myproperty", "foo");
}
}
The static initializer code will be executed before the spring application context is initialized.
How can I use env variables with Spring Boot Test?
During tests, it is better just use values from src/test/resources/application-test.properties:
secret=test secret
Please notice the filename, has this "test" suffix. It is there because Spring Boot runs tests in the "test" profile by default.
This properties file is a place to define your test configuration.
Choose good example values that will be used in your tests.
Do not inject example values for tests from the environment, as doing so will make your tests fail in one environment and pass in another.
To configure application properties for normal run use file src/main/resources/application.properties:
secret=${SECRET}
This way you can inject the environment variables to application properties using ${ENVIRONMENT_VARIABLE_NAME}
syntax.
Unlike during the test run where you want to stick to concrete example values, during the normal run of your application, is better to have your application properties to be injected from environment variables.
Now if you start your application like this:
export SECRET=secretFromEnv
mvn spring-boot:run
it will start with the application property "secret" having the value "secretFromEnv". Just like you had it like secret=secretFromEnv
, but it can be set differently in other environments (eg.: staging, production).
To use the application property value in your spring boot code, as mentioned in the question, @Value annotation can be used:
@Service
public class MyService {
@Value("${secret}")
private String secret;
public String getSecret() {
return secret;
}
}
And the test for this service can be like this:
class MyServiceTest extends IntegrationTestRunner {
@Autowired MyService service;
@Test
public void testSecret() {
var serviceSecret = service.getSecret();
assertEquals("test secret", serviceSecret);
}
}
This test asserts that the example value from the application config is returned by the service. During the actual run, the value will be injected from the environment variable, say if our environment variable is set:
export SECRET=secret-from-env
And the spring boot application is then started in this shell:
mvn spring-boot:run
So now say if in your rest controller there is code like this:
@Autowired MyService service;
@GetMapping(path = "/secret")
@ResponseBody public String getSecret() {
return service.getSecret();
}
Then calling HTTP GET /secret
will print "secret-from-env", as this is the value of environment variable $SECRET.
Doing this way:
- Allows us to have example application properties for tests;
- for non-test setup the values are injected from environment variables;
How to set environment variable dynamically in spring test
You can supply the password (or any Spring property) at runtime via System or Environment or Command Line variables. All of those sources are (a) defined at runtime and (b) external to your code base.
For example:
export password=...; java -jar app.jar
sets an environment variable namedpassword
which will then be present in your Spring Environmentjava -Dpassword=... -jar app.jar
sets a JVM system parameter which will then be present in your Spring Environmentjava -jar myapp.jar --password=...
sets a command line variable which will then be present in your Spring Environment
You can even source a property from JNDI.
More details in the docs.
How to set environment-variable in SpringBootTest for logback?
Using either @Before
, @BeforeAll
or a static
code block is too late to configure such variables for Logback.
You can solve this with a custom JUnit 5 extension:
public class PropertyExtension implements BeforeAllCallback {
@Override
public void beforeAll(ExtensionContext context) {
System.out.println("Setting system property");
System.setProperty("LOG_PATH", "/my/logpath/for/testing");
}
}
and use it within your test like:
@ExtendWith(PropertyExtension.class)
@SpringBootTest(classes = Application.class)
public class MyTestClass {
}
You can achieve the same with JUnit 4 with a custom ClassRule
. Read more on this here.
In addition, you might also set a default for such variables:
<appender name="plainLogsToFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/${LOG_PATH:-/tmp/default}/service.log</file>
</appender>
Related Topics
How to Get the First Date and Last Date of the Previous Month (Java)
Better Way to Detect If a String Contains Multiple Words
Use String.Split() With Multiple Delimiters
How to Post Form Data With Spring Resttemplate
How to Mock Classes With Constructor Injection
How to Call a Database Function Using Spring Data Jpa
Java 8 Streams: Multiple Filters Vs. Complex Condition
Get Unique Values from Arraylist in Java
Java: How to Check If Object Is Null
How to Return a HTML Page from a Restful Controller in Spring Boot
How to Use Jackson to Deserialise an Array of Objects
Duplicate Entry Exception: Spring Hibernate/Jpa Cascade Save Many to One
Finding Max Value in an Array Using Recursion
Open Pdf from Bytes Array in Angular 5
Javax.Xml.Bind.Unmarshalexception: Unexpected Element (Uri:"", Local:"Group")