2

In my Spring Boot project with IntelliJ IDEA Community, I'm creating integration tests with JUnit and Mockito, I want to set env variables globally because tests are many execution points, and in IntelliJ Community just I can set they for each run configuration. I'm using GNU/Linux, I set the env variables in my .bashrc and source the file, I define they in /test/resources/application-test.yml. When I run the tests throws an exception because it doesn't get the DB credentials, in this case, from the env variables. How it can read the values defined in .bashrc?

.bashrc


 # Obviously I setted the values, are empty just to show you

 export DB_URL_TEST=""
 export DB_USERNAME_TEST=""
 export DB_PASSWORD_TEST=""

/test/resources/application-test.yml


 spring:

  datasource:

    url: "${DB_URL_TEST}"
    username: "${DB_USERNAME_TEST}"
    password: "${DB_PASSWORD_TEST}"

    driver-class-name: org.mariadb.jdbc.Driver

The test in question:


 // It's in development, it's I have

 package com.latteIceCream.latte;

 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.http.MediaType;
 import org.springframework.test.context.ActiveProfiles;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
 import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

 @SpringBootTest
 @AutoConfigureMockMvc
 @ActiveProfiles("test")
 public class FlavorCRUDTest {

    @Autowired
    MockMvc mockMvc;

    @Test
    public void flavorRequest() throws Exception

    {

       mockMvc.perform
       (

          MockMvcRequestBuilders.post("/flavor/{name}")
          .contentType(MediaType.APPLICATION_JSON))
          .andExpect(status().isCreated())
          .andExpect
          (MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)

       );

    }

 }

2
  • Java's System.getenv() methods provide access to environment variables in the JVM's environment. Core Java has no special shortcuts for referring to these. I don't know about Spring, but I would be surprised if it did. Commented Jun 26 at 22:10
  • Please read docs.spring.io/spring-boot/reference/features/… Commented Jun 27 at 2:22

1 Answer 1

1

Why your approach is not a best practice

Your JVM has nothing to do with .bashrc, which is Bash-specific file, which is executed when you run Bash, as stated at gnu.org Bash docs.

When an interactive shell that is not a login shell is started, Bash reads and executes commands from ~/.bashrc, if that file exists.

Usually, you don't start Bash when you run your Java program. What is better, your program should never depend on any Linux specific programs and configurations. What if you run it under Windows, where there is no Bash? What if you run it on cloud Linux, e.g. Kubernetes, where environment is already set up by the provider?

I don't know what does many execution points mean. I assume you have multiple Spring Boot projects where you need to inject some global config.

Solution #1 (spring-dotenv library)

If you need to inject environment variables themselves, use me.paulschwarz:spring-dotenv library, which loads all variables from a provided .env file.

Define this .env file in the project root:

DB_URL_TEST=YOUR VALUE
DB_USERNAME_TEST=YOUR VALUE
DB_PASSWORD_TEST=YOUR VALUE

And that's it.

You can also configure it to load .env or other file using .env.properties, as stated in spring-dotetv docs:

directory=<string>
filename=<string>

Use this approach if you really need to use environment variables locally.

Solution #2 (externalized configuration)

This is more versatile approach, where Spring Boot can import external configurations via spring.config.import, which has more ways to inject configs.

If you test something locally, you can define a file with a set of static variables.

Define a .properties, .yaml or another file with all variables, which can be consumed by Spring Boot.

An example of global.yaml at /home/user/global.yaml:

spring:
  datasource:
    url: "YOUR VALUE"
    username: "YOUR VALUE"
    password: "YOUR VALUE"

Then consume it by Spring Boot with the following property in application-test.properties:

spring.config.import=file:/home/user/global.properties

Alternatively, you can supply it as a JVM parameter:

-Dspring.config.import=file:/home/user/global.properties

Use this approach if you have a need to use Spring Boot-specific configs or some else YAML or other configs.

Testing

Both variants can be tested in the following way:

@SpringBootTest
@ActiveProfiles("test")
public class LoadGlobalProperties {
  @Value("${spring.datasource.url}")
  private String url;

  @Test
  void shouldShowGlobalVariable() {
    assertEquals("YOUR VALUE", url);
  }
}

Source:

Sign up to request clarification or add additional context in comments.

1 Comment

With "execution points" I mean the "green play button" in the class and the tests methods. IntelliJ you can set in the run configurations of they the env variables. I tried it with the correct DB credentials, but the errors says that the access is denied for the DB user. In MariaDB I was granted the priveleges to the user for the DB.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.