Spring profiles and testing

ぃ、小莉子 提交于 2019-12-12 07:09:34

问题


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?


回答1:


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



回答2:


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.




回答3:


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.




回答4:


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"/>


来源:https://stackoverflow.com/questions/13364112/spring-profiles-and-testing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!