Spring Boot profile properties doesn't work with tests - java

Spring Boot version 2.2.6. I have case that there is several application-{profile}.yml files in folder src/main/resources/ and I want't to build project with Maven e.g mvn clean package -Dspring.profiles.active=dev
Then I have just application.yml file in folder src/test/resources, this should be a properties file to all test (IT/unit).
Now when I build with command mvn clean package -Dspring.profiles.active=dev, properties src/main/resources/application-dev.yml and src/test/resources/application.yml are MERGED and used for the tests. Well in test properties there might be pretty fatal confs e.g Hibernate auto-ddl: create-drop.
Have been reading docs but I don't find any logic why properties files are MERGED in this case. Is there any good practice that tests can be forced to use ALWAYS certain properties file? I think that just using some annotations in test files isn't the best practice, e.g #TestPropertySource or #ActiveProfiles, cause when you forgot to use these annotations then the case is same again. Is there some global configuration for all tests or some other better solutions?

The application.yml file has higher precedence over any environment-specific file, for example, application-dev.yml file. The standard inheritance applies, so you can override the parent properties in the profile-specific YAML file.
application.yml
server:
port: 9090
spring:
jpa:
hibernate:
ddl-auto: create-drop
application-dev.yml
spring:
jpa:
hibernate:
ddl-auto: none
In case you run with the dev profile, the value of spring.jpa.hibernate.ddl-auto parameter would be none.

I get that application.yml has higher precedence in folder /src/main, but that it takes over also from folder /src/test is kinda weird.
Yes that config can be made into profile-specific files (ddl-auto: none), tough I still have problem with datasource, somehow Spring Boot is picking application-dev.ymls datasource into tests also, this is working like other way around than that ddl-auto attribute.
src/test/resources/application.yml
spring:
datasource:
url: jdbc:h2:mem:test;DB_CLOSE_ON_EXIT=FALSE;MODE=PostgreSQL
src/main/resources/application-dev.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/db

Related

How to autoselect springprofile when running tests

I am looking for a solution to automatically add the environment variable SPRING_PROFILES_ACTIVE="test" when running unit-tests. The solution should fulfill the following criteria :
Ideally it should be configured via maven pom.xml
If 1 is not possible configuration should be done for IntelliJ via configuration file in the project not via UI setting
The particular environment variable should only be set when running unit tests not when generally launching the app.
Any idea on how to approach this goal is appreciated.
Best
Andy
The SPRING_PROFILES_ACTIVE is a property value that should be set in a file like application-test.properties or application-test.yml
In a yml file it would look like,
spring:
profiles:
active: test
Additionally, there are specific annotations to help identify certain classes/methods as test specific such as #Profile("test") or #ActiveProfiles("test").

How can a library module of a Spring application add additional configuration to the application's `application.yml`?

I have a Spring Boot application built with Maven which uses JDBC. The application.yml file has
spring:
application:
(stuff)
datasource:
url: jdbc:informix-sqli://......
driver-class-name: com.informix.jdbc.IfxDriver
I want to move the JDBC specific parts into a library so now the app/src/main/resources/application.yml only contains
spring:
application:
(stuff)
and the datasource configuration parameters need to live in the library repository. I tried creating lib/src/main/resources/application.yml with
spring:
datasource:
url: jdbc:informix-sqli://......
driver-class-name: com.informix.jdbc.IfxDriver
hoping that both the yml files would be picked up and merged when Spring loads up. Apparently not.
The library and application build fine, but when I run it
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
How can I get the configuration in the library to be merged into the application.yml configuration in the application?
I have always found "merging" of external configuration from sub-modules with spring-boot to be problematic at worst, confusing at best. I now organize all external configuration using one of two approaches. But first, there are multiple ways to specify external configuration that you should be aware of:
Spring Boot and multiple external configuration files
Starting Spring Application by merging yml files
https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config
I previously would specify multiple locations and that sort-of worked. But, I now typically use one of two approaches to avoid confusion:
I use profiles and specify multiple profiles at runtime when launching the spring boot app. i.e. Multiple profiles like "shared-common, shared-jdbc, deploy-prod" which will load "application-shared-jdbc.yml" out the sub-module.
or
I create a module that contains nothing but configuration files that get used by all related modules, often with multiple profiles for different configuration scenarios. All other modules (executable and libraries) depend on this shared configuration module.
AFAICT, spring-boot's external configuration handling not setup ideally for having standalone submodule configuration. It's more oriented around the notion that configuration belongs to runtime/executable modules, not libraries.
you can use #PropertySource. you have to implement your own PropertySourceFactory
if your props is in yaml format. then define it in the PropertySource
#PropertySource(value = ResourceUtils.CLASSPATH_URL_PREFIX
+ "application.yml", factory = Factory.class)

spring boot multi-line import.sql application.yml configuration

I have a spring boot application configured with an application.yml file. I'm also using an import.sql file to load test data into my application using insert statements.
I want the import.sql to support multiline statements.
I found this similar question with an answer using and application.properties file Spring Mvc Hibernate Encoding/Multi-line import sql
However I can't seem to apply that answer to using my application.yml file which I have tried unsuccessfully to do as below
spring:
jpa:
show-sql: true
hibernate:
hbm2ddl:
import_files_sql_extractor:org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor
For reference I found the documentation for this property here https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/tool/hbm2ddl/ImportSqlCommandExtractor.html
But I still can't seem to configure it properly. Can anyone help? Thanks
I got multi-line import.sql statements working for Spring Boot 2 by adding property prefix "spring.jpa.properties".
So for application.yml configuration it is:
spring:
jpa:
properties:
hibernate:
hbm2ddl:
import_files_sql_extractor: org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor
in application.yml you can add config:
spring:
datasource: classpath:/init.sql
or add #SQL(value = "data.sql") annotation in your test class where data.sql has multiple lines sql commands.

Managing dependencies with spring boot profiles and Gradle

I created a java project that will use spring boot and Gradle. I would like to configure profiles, for the different environment (development on my local machine, systemtest for integration test on server farm machine etc). I would use h2 in memory database for development environment and SqlServer for systemtest environment. In build.gradle I defined the following dependencies
dependencies {
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-web-services")
compile('org.springframework.boot:spring-boot-starter-actuator')
runtime('com.h2database:h2:1.4.195')
runtime('com.microsoft.sqlserver:mssql-jdbc')
}
I created a application.yml file, application-development.yml and application-systemtest.yml where I would put common properties and environment specific properties. The file application-systemtest.yml defines the connecction parameters for sql server
spring:
datasource:
url: jdbc:sqlserver://<host>,1433;databaseName=MYDB
username: myuser
password: mypass
driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
jpa:
show-sql: true
hibernate:
dialect: org.hibernate.dialect.SQLServer2012Dialect
I would also create an uber-jar and select the profile as a launch parameter, ie
java -Dspring.profiles.active=systemtest -jar <my uber jar>
The development profiles starts fine and I am running on h2 in memory database. When trying systemtest profile, spring boot fails to load contexts and fails. This is caused by spring boot finding h2 dependency and trying to configure datasource defined in application-systemtest.yml
So I modified the build.gradle dependencies closure
def profile = project.findProperty('spring.profiles.active')
dependencies {
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-web-services")
compile('org.springframework.boot:spring-boot-starter-actuator')
if (profile == 'development') {
runtime('com.h2database:h2:1.4.195')
} else {
runtime('com.microsoft.sqlserver:mssql-jdbc')
}
}
This time spring boot start correctly. Don't like very much this solution as I have to handle the profile configuration partly with Gradle. I would like to know if there is a way to configure spring boot so that profile is completely managed within itself, resolving h2 in development environment and sqlserver in systemtest environment, leaving Gradle unaware of spring profiles.
How to solve this problem ?
It wouldn't be advisable to have a different artifact / binary depending on the DB product. Try to configure the datasources / Spring profiles as suggested by #M. Deinum to prevent the datasource to be configured as H2 when using a different DB.

Spring Datasources based on Environment

I am trying to configure my Spring Boot application to use specific datasources when certain environmental variables exist. For example, if the MY_PROD_DATASOURCE environmental variable exists, I would like to use my production datasource; otherwise, I would like to use my local datasource (of the same type).
I have found something in the Spring reference that explains how a single datasource could be declared in my application.properties. Specifically, a MySQL datasource could look like:
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driverClassName=com.mysql.jdbc.Driver
However, I do not see how I could change the datasource properties conditionally in this file. Is there another way to do it?
In Spring Boot you can:
Externalize application.properties from your jar and provide file per environment by adding path as a startup parameter:
java -jar your-app.jar --spring.config.location=/path/to/app.properties
Use Spring profiles. Create application-${profile}.properties for each profile, in each one different datasource properties
Use Spring profiles and instead of application.properties, put your properties to application.yaml where you can put properties for all environments using convention as below:
spring:
profiles: development
server:
port: 9001
---
spring:
profiles: production
server:
port: 0
Use environment variables and set SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME, SPRING_DATASOURCE_PASSWORD, and (optionally) SPRING_DATASOURCE_DRIVER_CLASS_NAME.
Learn more in the Spring Boot reference section on How to change configuration depending on the environment and External Configuration.

Categories

Resources