弹簧配置文件和测试
Posted
技术标签:
【中文标题】弹簧配置文件和测试【英文标题】: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 中声明变量吗?
【问题讨论】:
【参考方案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
从命令行加载配置吗?似乎上述建议将您修复到特定配置中。以上是关于弹簧配置文件和测试的主要内容,如果未能解决你的问题,请参考以下文章