为测试加载系统属性

3
我最近找到了一个解决方案,可以让我在单元测试中加载系统属性。如果我只运行一个测试,它的效果很好,但如果我选择运行整个测试套件,它就会失败。有人能告诉我为什么吗? 第一步是加载测试应用程序上下文:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/applicationContext-test.xml")
下一步是创建一个类来加载系统属性:
import java.io.InputStream;
import java.util.Properties;

import javax.annotation.PostConstruct;

import org.springframework.core.io.Resource;

public class SystemPropertiesLoader{

    private Resource resource;

    public void setResource(final Resource resource){
        this.resource = resource;
    }

    @PostConstruct
    public void applyProperties() throws Exception{

        final Properties systemProperties = System.getProperties();

        final InputStream inputStream = resource.getInputStream();

        try{
            systemProperties.load(inputStream);
        } finally{
            inputStream.close();
        }
    }
}
最后一步是将这个bean列入我的测试应用程序上下文中:
<bean class="com.foo.SystemPropertiesLoader">
    <property name="resource" value="classpath:localdevelopment_Company.properties" />
</bean>
当我运行测试套件时,我的一些测试都会失败,这些测试都依赖于系统属性。如果我进入特定的测试并运行它,那么它将通过。我已经进行了调试,并验证了 SystemPropertiesLoader 中的代码正在执行,并且所有其他 bean 都可以成功地从上下文中获取。然而,属性没有被正确加载,因为当我尝试访问它们时,它们全部为空。有什么建议吗?
3个回答

3
几个想法:
  1. 如果你在进行单元测试,为什么不在每个单独的测试用例中设置所需的属性。使用Spring设置全局变量没有意义。
  2. 为什么使用系统属性。Spring管理属性对象,您可以将它们注入到您的bean中。它们可以在appContext.xml中设置,并在那里初始化(参见:PropertyPlaceHolderConfigurer),使用系统属性。让您的代码访问系统属性违反了Spring的哲学。
  3. 从文件设置系统属性本来就是错误的。通常你会使用系统属性来覆盖属性文件中的设置。

谢谢!我尝试了PropertyPlaceholderConfigurer,它非常好用。我需要让其他开发人员看看是否同意在整个应用程序中采用这种方法,但它确实解决了问题。 - Samo
我进一步研究了这种方法,想知道是否有更好的方法适用于我们。我们希望能够静态引用我们的属性,但是让Spring初始化静态值非常困难。我们不想每次需要属性时都实例化一个类,也不想使用具有所有属性的bean。我们想要静态访问不可变字符串。有什么建议吗? - Samo
嗨Samo,为什么你不想用所有属性来实例化一个bean呢?如果它是应用程序范围的,它只会被实例化一次。此外,您可以考虑为参数创建一个bean,该bean具有真正的Java属性(即字段和getter)。然后,您可以在javadoc中记录应用程序接收到的参数... - Felix Leipold
除非我弄错了,否则实例化一个带有所有属性的bean需要使用每个属性的设置器。如果我有设置器,那么我可以更改此bean中属性的值。我希望这些值是最终值。 - Samo
构造函数参数?我通常更喜欢它们而不是setter注入。此外,难道没有通过反射设置字段的方法(自动装配可以做到这一点)吗? - Felix Leipold

2
问题实际上是Properties类的值被静态定义了。以下是导致解决方案失败的情况: 1. 运行测试A。测试A没有加载applicationContext-test.xml,但调用使用Properties类值的代码。 2. 现在,所有来自Properties类的值都被永久定义了。 3. 运行测试B。测试B加载applicationContext-test.xml。 4. SystemPropertiesLoader运行,将值加载到系统属性中。 5. 从Properties类检索一个值,但由于它们是静态定义并且之前已经赋值,因此系统属性中的值从未进入其中。 最终,最好的解决方案是在Properties类中定义默认值。

0

你的测试用例是否每次都会生成一个新的JVM,导致每个测试用例中的System属性没有被正确设置?

建议尝试在JUnit测试类中利用setUp()tearDown()方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,