fongfong
fongfong

Reputation: 175

Spring boot - How to provide environment variables to app context to avoid unit test failure

I have a spring boot REST API app. I am using environment variables in application.properties file. Some settings are as shown below:

logging.level.springframework.web=${WEB_LOG_LEVEL}
logging.level.org.hibernate=${HIBERNATE_LOG_LEVEL}

In my unit test, I use annocation @TestPropertySource("classpath:application-test.properties"). However, when I run mvn clean install, build fails because of unit test failure. I provided the error log. When I ran in IDE, I can provide those environment vairables. Any suggestions on how to pass them in mvn clean install? Or any other approaches you would recommend? Thanks much in advance!

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to bind properties under 'logging.level.springframework.web' to org.springframework.boot.logging.LogLevel:

    Property: logging.level.springframework.web
    Value: ${WEB_LOG_LEVEL}
    Origin: class path resource [application.properties] - 44:35
    Reason: failed to convert java.lang.String to org.springframework.boot.logging.LogLevel (caused by java.lang.IllegalArgumentException: No enum constant org.springframework.boot.logging.LogLevel.${WEB_LOG_LEVEL})

Action:

Update your application's configuration. The following values are valid:

    DEBUG
    ERROR
    FATAL
    INFO
    OFF
    TRACE
    WARN

Upvotes: 2

Views: 2899

Answers (1)

xerx593
xerx593

Reputation: 13261

We have many options!

Best is we (roughly) understand the 2 Externalized Configuration and PropertySource:

  1. Leaving our application.properties as it is, we can:

    1. (As tgdavies commented), introduce src/test/resources/application... Here we can:

      • call it application.properties, and it will override (existing settings/"sensible") of src/main/resources/application.properties, then we don't need @PropertySource or @Profiles on our test.
      • call it application_test.properties, then work rather with @Profile("test") + @ActiveProfiles("test") (on our test class(es), with even higher precedence as the above).
      • don't use @PropertySource (some_custom_name.properties file) for this use case, it has too low precedence!

      ...in these properties we will write (without placeholders):

      logging.level.springframework.web=warn
      logging.level.org.hibernate=warn
      # or the log level(s) of our choice, overriding(!) the "main ones"
      
    2. SET/EXPORT these properties in our (dev) environment! (with our cli/OS dialog/MAVEN_OPTS/...)

    3. Using @TestPropertySource (2nd highest precedence, in spring-boot configuration hierarchy!, no profiles):

      • like (override property):
        @TestPropertySource(properties = "logging.level.springframework.web=warn", ...)
        
      • or (using/trying relaxed binding):
        @TestPropertySource(properties = "web.log.level=warn", ...)
        
      • or (using a file):
        @TestPropertySource(locations = "classpath:/some/properties.properties", ...)
        
  2. But a slight modification of our (src/main/...)application.properties can also be very helpful: Fallback! - looks like:

    logging.level.springframework.web=${WEB_LOG_LEVEL:warn}
    logging.level.org.hibernate=${HIBERNATE_LOG_LEVEL:warn}
    

    It tries for the environment variables, and falls back to warn. With this, we can omit @PropertySource/@Profile and/or an additional test-application-properties.

    And even better with relaxed binding:

    logging.level.springframework.web=${web.log.level:warn}
    logging.level.org.hibernate=${hibernate.log.level:warn}
    

    This will accept the above environment variables, but also (previously defined)"properties" + fall back to "warn".

  3. Conflict-free combinations of the proposed.

  4. ... -> Chapter 2, Relaxed Binding(, Profiles!) and Spring Boot How To: Properties and Configuration.

Upvotes: 3

Related Questions