0
votes

I have been using Spring Boot and TestNG for my test framework and so far my tests were configured to use only one default application.properties file which is under src/main/resource. Now I want to configure them for different environments - ci/stage etc. I have used spring documentation to activate the profiles from pom.xml file.

 <profiles>
    <profile>
        <id>ci</id>
        <properties>
            <activeProfile>ci</activeProfile>
        </properties>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
</profiles>

I have for two properties files under src/main/resources - application.properties and application-ci.properties. (The is the naming convention suggested by spring documentation. application-{activatedprofile}.properties).

The application.properties have got a placeholder -

spring.profiles.active=@activeProfile@

The @activeProfile@ will get replaced with the value of activeProfile in the pom.xml file.And uptil that it is working.

In my @Configuration class I have a annotation as below and I am expecting that the ${spring.profiles.active} value gets replaced with value - ci.

 @PropertySource("classpath:application-${spring.profiles.active}.properties")

I am getting following error:

java.lang.IllegalArgumentException: Could not resolve placeholder 
'spring.profiles.active' in value 
"classpath:application-${spring.profiles.active}.properties"

I am using maven and testng to run my project. I am doing something incorrect let me know how can I resolve it.

1
how @activeProfile@ replaced for tests in your code? actually for tests you could use @ActiveProfiles("ci") together with @SpringBootTest - Vasyl Sarzhynskyi
You should prevent having maven profiles in your spring boot apps..Otherwise I would take that as a code smell... - khmarbaise
Maven profiles != Spring Profiles. Also you shouldn't use profiles like that as that will result in different builds for different environments. You don't want to do that (as that basically means you are going to production untested). In your @PropertySource you are also trying to outsmart Spring Boot (which already does all that for you, so you don't need it). Just pass the profile you want you use during startup of your application (or through an environment variable or simply by @ActiveProfiles on your test classes. - M. Deinum
@m-deinum just to clarify if I use "@ActiveProfiles("ci")" on my "@Configuration" class then the test will pick application-ci.properties file and replace all the properties from file in test? - Galileo123

1 Answers

0
votes

First of all, the maven profile is not the same as the spring profile. In the code snippet provided you are setting the maven profile, not the spring profile.

To pass a specific spring profile during your test phase you can use the surefire plugin. In the code snippet below you would be passing in the system property spring.profiles.active as ci. This is equivalent to setting the value in your application.properties file.

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.0</version>
    <configuration>
      <systemPropertyVariables>
        <spring.profiles.active>ci</spring.profiles.active>
      </systemPropertyVariables>
    </configuration>
  </plugin>

Secondly, spring will automatically load the property sources based on the active spring profile. In your example, spring will first load application.properties then it will apply application-ci.properties on top of it. As a result

@PropertySource("classpath:application-${spring.profiles.active}.properties")

is not needed.

If you have a configuration class that is specific to an active profile then you can add @ActiveProfiles("ci") to your configuration class and it will only use that class when the profile ci is active.

Lastly, you do not need the property spring.profiles.active=@activeProfile@ in your application.properties files as this be passed in from the surefire plugin in maven.