[java] Spring profiles and testing

I've got a web application where I have the typical problem that it requires different configuration files for different environments. Some configuration is placed in the application server as JNDI datasources, however some configuration stays in property files.

Therefore I want to use the Spring profiles feature.

My problem is that I don't get the test case running.

context.xml:

<context:property-placeholder 
  location="classpath:META-INF/spring/config_${spring.profiles.active}.properties"/>

Test:

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({
    TestPreperationExecutionListener.class
    })
@Transactional
@ActiveProfiles(profiles = "localtest")
@ContextConfiguration(locations = {
    "classpath:context.xml" })
public class TestContext {

  @Test
  public void testContext(){

  }
}

The problem seems to be that the variable for loading the profile isn't resolved:

Caused by: java.io.FileNotFoundException: class path resource [META-INF/spring/config_${spring.profiles.active}.properties] cannot be opened because it does not exist
at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:157)
at org.springframework.core.io.support.PropertiesLoaderSupport.loadProperties(PropertiesLoaderSupport.java:181)
at org.springframework.core.io.support.PropertiesLoaderSupport.mergeProperties(PropertiesLoaderSupport.java:161)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.postProcessBeanFactory(PropertySourcesPlaceholderConfigurer.java:138)
... 31 more

The current profile should be set with the @ActiveProfile annotation. As it's a test case I won't be able to use the web.xml. If possible I'd like to avoid runtime options as well. The test should run as is (if possible).

How can I properly activate the profile? Is it possible to set the profile with a context.xml? Could I declare the variable in a test-context.xml that is actually calling the normal context?

This question is related to java spring junit profile

The answer is


Can I recommend doing it this way, define your test like this:

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({
    TestPreperationExecutionListener.class
    })
@Transactional
@ActiveProfiles(profiles = "localtest")
@ContextConfiguration
public class TestContext {

  @Test
  public void testContext(){

  }

  @Configuration
  @PropertySource("classpath:/myprops.properties")
  @ImportResource({"classpath:context.xml" })
  public static class MyContextConfiguration{

  }
}

with the following content in myprops.properties file:

spring.profiles.active=localtest

With this your second properties file should get resolved:

META-INF/spring/config_${spring.profiles.active}.properties

Looking at Biju's answer I found a working solution.

I created an extra context-file test-context.xml:

<context:property-placeholder location="classpath:config/spring-test.properties"/>

Containing the profile:

spring.profiles.active=localtest

And loading the test with:

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({
    TestPreperationExecutionListener.class
    })
@Transactional
@ActiveProfiles(profiles = "localtest")
@ContextConfiguration(locations = {
    "classpath:config/test-context.xml" })
public class TestContext {

  @Test
  public void testContext(){

  }
}

This saves some work when creating multiple test-cases.


@EnableConfigurationProperties needs to be there (you also can annotate your test class), the application-localtest.yml from test/resources will be loaded. A sample with jUnit5

@ExtendWith(SpringExtension.class)
@EnableConfigurationProperties
@ContextConfiguration(classes = {YourClasses}, initializers = ConfigFileApplicationContextInitializer.class)
@ActiveProfiles(profiles = "localtest")
class TestActiveProfile {

    @Test
    void testActiveProfile(){

    }
}

The best approach here is to remove @ActiveProfiles annotation and do the following:

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({
    TestPreperationExecutionListener.class
    })
@Transactional
@ContextConfiguration(locations = {
    "classpath:config/test-context.xml" })
public class TestContext {

  @BeforeClass
  public static void setSystemProperty() {
        Properties properties = System.getProperties();
        properties.setProperty("spring.profiles.active", "localtest");
  }

  @AfterClass
  public static void unsetSystemProperty() {
        System.clearProperty("spring.profiles.active");
  }

  @Test
  public void testContext(){

  }
}

And your test-context.xml should have the following:

<context:property-placeholder 
  location="classpath:META-INF/spring/config_${spring.profiles.active}.properties"/>

public class LoginTest extends BaseTest {
    @Test
    public void exampleTest( ){ 
        // Test
    }
}

Inherits from a base test class (this example is testng rather than jUnit, but the ActiveProfiles is the same):

@ContextConfiguration(locations = { "classpath:spring-test-config.xml" })
@ActiveProfiles(resolver = MyActiveProfileResolver.class)
public class BaseTest extends AbstractTestNGSpringContextTests { }

MyActiveProfileResolver can contain any logic required to determine which profile to use:

public class MyActiveProfileResolver implements ActiveProfilesResolver {
    @Override
    public String[] resolve(Class<?> aClass) {
        // This can contain any custom logic to determine which profiles to use
        return new String[] { "exampleProfile" };
    }
}

This sets the profile which is then used to resolve dependencies required by the test.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to spring

Are all Spring Framework Java Configuration injection examples buggy? Two Page Login with Spring Security 3.2.x Access blocked by CORS policy: Response to preflight request doesn't pass access control check Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified Spring Data JPA findOne() change to Optional how to use this? After Spring Boot 2.0 migration: jdbcUrl is required with driverClassName The type WebMvcConfigurerAdapter is deprecated No converter found capable of converting from type to type

Examples related to junit

Eclipse No tests found using JUnit 5 caused by NoClassDefFoundError for LauncherFactory How to resolve Unneccessary Stubbing exception JUnit 5: How to assert an exception is thrown? How do I mock a REST template exchange? Class Not Found: Empty Test Suite in IntelliJ Unable to find a @SpringBootConfiguration when doing a JpaTest Failed to load ApplicationContext (with annotation) Example of Mockito's argumentCaptor Mockito - NullpointerException when stubbing Method Spring jUnit Testing properties file

Examples related to profile

Missing Push Notification Entitlement Spring profiles and testing How to add /usr/local/bin in $PATH on Mac Do you know the Maven profile for mvnrepository.com? A valid provisioning profile for this executable was not found for debug mode Getting the "real" Facebook profile picture URL from graph API How to reload .bashrc settings without logging out and back in again? What's the best free C++ profiler for Windows?