32

I am working with JUnit 5. My Java code uses the System.getenv("demoVar") to access environment variables.

How do I set up this environment variable in a JUnit 5 test class so that my code can access its value during the test?

1
  • 3
    With Java 8, you could change your method that calls System.getenv() so that it uses a Function<String, String> instead. In your production code, you would use System::getenv, and in your test code, you can use Map::get on an internal map that you filled with test values. Commented Mar 3, 2020 at 15:42

6 Answers 6

20

From this other SO answer https://stackoverflow.com/a/59635733/2185719:

There is JUnit Pioneer, a "JUnit 5 extension pack".

jUnit Pioneer offers an annotation that sets environment variables for a test. For example:

@Test @SetEnvironmentVariable(key = "PATH", value = "") void testPath_isEmpty() { assertThat(System.getenv("PATH")).isEmpty(); } 
Sign up to request clarification or add additional context in comments.

5 Comments

This would give a warning from JDK9-16 and throws InaccessibleObjectException in JDK17.
There's an issue in the library's repository discussing the warnings and errors around using this annotation. It also offers ways to work around it. github.com/junit-pioneer/junit-pioneer/issues/509
Thanks for the info @Miguel Ferreira. (They are still work arounds, we are planning to remove env variable dependency instead of using the work arounds). Thanks again for your time
@Bala Pioneer dedicated an entire section to this "issue": junit-pioneer.org/docs/environment-variables/…
But this logic is breaking with Spring Boot 3.3.9
8

You can't within the actual java process because these environmental values using getenv are immutable.

One way would be to start another vm or another process where you could introduce your new environment value.

Another way would be to switch to System.getProperty, but be sure you understand the differences.

https://www.baeldung.com/java-system-get-property-vs-system-getenv

Here is a little testcode:

public class EnvironmentVarsTest { private static int counter = 0; @BeforeEach public void setUp() { counter = counter + 1; System.setProperty("simple_test_env_property", String.valueOf(counter)); } @Test public void testFirst() { printOutValues(); } @Test public void testSecond() { printOutValues(); } private void printOutValues() { System.out.println("--------------------"); System.out.println("val=" + counter); System.out.println("envval=" + System.getProperty("simple_test_env_property")); } } 

2 Comments

There is a hack that lets you set environment variables for the current process from Java code. It's not pretty and you shouldn't use it unless you really need it. On the other hand, Java should really have a proper method to do this without resorting to hacks.
Note: there are libraries that let you do this easily. However, from Java 16 onwards, the reflection hacks no longer work. github.com/webcompere/system-stubs has a mockito-based solution to this which does work.
7

Simple solution if you use Gradle, you can add following to your build.gradle

test { environment "ENV_VAR_NAME", "ENV_VAR_VALUE" } 

Link to Gradle doc: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html#org.gradle.api.tasks.testing.Test:environment

1 Comment

this sets the variable for all tests though.
4

This can be achieved with https://github.com/webcompere/system-stubs/tree/master/system-stubs-jupiter

 @ExtendWith(SystemStubsExtension.class) class TestClass { @SystemStub private EnvironmentVariables environmentVariables = new EnvironmentVariables("demoVar", "val"); @Test void test() { // can use the environment assertThat(System.getenv("demoVar")).isEqualTo("val"); // can also change the environment environmentVariables.set("foo", "bar"); // environment variables restored to previous state when // test ends } } 

2 Comments

does not work with kotlin v1.9 and java 17
Please raise an issue on the github project. It definitely can work with Java 17, though won't survive multi-threaded code.
2

Here is a solution using Kotlin DSL (build.gradle.kts):

tasks.withType<Test> { environment["myFirst"] = "bunny" // OR environment( "mySecond" to "7249", "myThird" to "curtain" ) } 

The environment variables will be available both in the tests and in the main code:

val name = System.getenv().get("myFirst") 

Sidenote: You can also disable/enable your tests based on environment variables:

@Test @EnabledIfEnvironmentVariable(named = "myFirst", matches = "bunny", disabledReason = "Oh no") public void myTest() { // ... } 

Comments

0

The common practice is to use System properties instead of environment variables. In this case you will run your java/maven/gradle command or whatever you use to run your tests with option -D demoVar="{your_value}". for maven goal:

 maven clean install -DdemoVar="test" 

for java jar:

 java -jar xxx.jar -DdemoVar="test" 

You will be able to get it from code with System.getProperty("demoVar").

If you really need to use environment variable, use OS functionality. For linux:

demoVar="test" mvn clean install 

For windows PowerShell:

$env:demoVar = 'test'; mvn clean install 

1 Comment

Thanks! $env:demoVar = 'test'; mvn clean install - quick simple and works

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.