【问题标题】:Spring profiles and testing弹簧配置文件和测试
【发布时间】:2012-11-02 01:56:19
【问题描述】:

我有一个 Web 应用程序,其中存在一个典型问题,即它需要针对不同环境使用不同的配置文件。一些配置作为 JNDI 数据源放置在应用服务器中,但是一些配置保留在属性文件中。

因此我想使用 Spring 配置文件功能。

我的问题是我没有让测试用例运行。

context.xml:

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

测试:

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

  @Test
  public void testContext(){

  }
}

问题似乎是加载配置文件的变量没有解决:

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

应使用@ActiveProfile 注释设置当前配置文件。由于这是一个测试用例,我将无法使用web.xml。如果可能的话,我也想避免运行时选项。测试应按原样运行(如果可能)。

如何正确激活配置文件?是否可以使用 context.xml 设置配置文件?我可以在实际调用正常上下文的 test-context.xml 中声明变量吗?

【问题讨论】:

    标签: java spring junit profile


    【解决方案1】:

    我可以推荐这样做吗,像这样定义你的测试:

    @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{
    
      }
    }
    

    在 myprops.properties 文件中包含以下内容:

    spring.profiles.active=localtest
    

    有了这个你的第二个属性文件应该得到解决:

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

    【讨论】:

    • 这种方法不干净,您必须转到应该更改活动配置文件值的属性文件。
    【解决方案2】:

    看着 Biju 的回答,我找到了一个可行的解决方案。

    我创建了一个额外的上下文文件test-context.xml

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

    包含简介:

    spring.profiles.active=localtest
    

    并加载测试:

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

    这在创建多个测试用例时节省了一些工作。

    【讨论】:

    • 所以每次你想运行一个测试你必须去 test-context.xml 并更改属性文件路径,如果想加载另一个属性?这与 Spring Profiles 的想法相矛盾。看看我在这种情况下的解决方案。
    • @CodeBusta 不,它是一个 test-context.xml,仅用于加载常规上下文的测试。
    【解决方案3】:
    public class LoginTest extends BaseTest {
        @Test
        public void exampleTest( ){ 
            // Test
        }
    }
    

    从基础测试类继承(这个例子是testng而不是jUnit,但ActiveProfiles是一样的):

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

    MyActiveProfileResolver 可以包含确定使用哪个配置文件所需的任何逻辑:

    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" };
        }
    }
    

    这会设置配置文件,然后用于解决测试所需的依赖关系。

    【讨论】:

      【解决方案4】:

      这里最好的方法是删除@ActiveProfiles 注释并执行以下操作:

      @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(){
      
        }
      }
      

      你的 test-context.xml 应该有以下内容:

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

      【讨论】:

      • 在@AfterClass 中使用静态属性而不清理它们会导致严重的、难以分析的问题。
      • 好吧,正如我所说:至少在 AfterClass 方法中通过 System.clearProperty() 清理属性。或者使用一些规则,如stefanbirkner.github.io/system-rules
      • 我明白了,但是在这个特定示例中清理的原因是什么?每个测试都使用自己的上下文运行,因此您不必清理系统属性。如果我错了纠正我。我刚刚添加了请求的清理部分,但我不明白这里为什么需要它。
      • 不要这样做。我会告诉你这是一种极其不可靠的方法。问题在于没有使用 Spring 的特殊 @ActiveProfiles 它将缓存应用程序上下文。缓存键基于@ContextConfiguration(locations = {})。至于更改系统属性,如果您想同时运行测试,那么您真的是 *#!$#@ 自己,这是完全错误的:“每个测试都使用自己的上下文运行,因此您不必清理系统属性" 。只有当你有 Surefire/JUnit 分叉时才有效。
      • 只是不要使用这种方法。
      【解决方案5】:

      @EnableConfigurationProperties 需要在那里(你也可以注释你的测试类),来自 test/resources 的 application-localtest.yml 将被加载。 使用 jUnit5 的示例

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

      【讨论】:

      • 你能使用-Dspring.profiles.active=name从命令行加载配置吗?似乎上述建议将您修复到特定配置中。
      猜你喜欢
      • 2011-11-27
      • 1970-01-01
      • 2016-04-26
      • 2016-12-13
      • 1970-01-01
      • 2021-12-12
      • 1970-01-01
      • 1970-01-01
      • 2018-11-27
      相关资源
      最近更新 更多