How to Set Environment Variable or System Property in Spring Tests

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 named password which will then be present in your Spring Environment
  • java -Dpassword=... -jar app.jar sets a JVM system parameter which will then be present in your Spring Environment
  • java -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



Leave a reply



Submit