【问题标题】:Unit testing with a static final field from system properties使用来自系统属性的静态最终字段进行单元测试
【发布时间】:2018-06-20 14:19:40
【问题描述】:

我有一个带有从系统属性中提取的公共静态最终字段的接口。它看起来像这样:

public interface MyInterface {
    public static final String MYFIELD = System.getProperty("MyField");
    ...
}

我正在编写一个使用该字段的单元测试。即使我在测试前在静态初始化程序中设置了系统属性,接口字段也会返回 null

System.out.println(System.getProperty("MYField")); //returns "MyField"
System.out.println(MyInterface.MYFIELD); //returns null

为什么没有设置接口字段?处理这种情况的最佳方法是什么?我不能只在测试中设置字段值,因为它是最终静态的。

更新:

我可能错过了一个重要的细节;我正在使用 Mocktio。它看起来像这样

public class MyTest {

    static {System.setProperty("MyField", "MyValue");}

    @Test
    public void test1() {
        try {
            final MyInterface mockInterface = Mockito.mock(MyInterface.class);
            ...
        }
     }
}

【问题讨论】:

  • 静态初始化器在类加载时执行。当第一次在代码中(而不是在导入中)引用一个类时,它就会被加载。因此,您需要在首次调用 MyInterface 之前设置系统属性。

标签: java junit


【解决方案1】:

对您来说坏消息:由于是静态的,MYFIELD 字段在加载 MyInterface 时进行评估。因此,如果您的测试类有对MyInterface 的静态引用,它会与您的测试类同时加载。因此,您无法在执行测试之前通过代码设置系统属性。

我怀疑您是否使用了一种好的方法:通常,接口应该代表一种行为,而不仅仅是一堆任意常量。但是,如果您确实需要在接口的成员中存储一些常量值,那么从系统属性中获取这些值是无稽之谈:常量旨在精确地成为 常量

如果您需要您的程序依赖于任意值,它们应该作为输入参数(在构造函数或方法中)接收,正是为了让您有机会在制作时根据自己的意愿设置它们的值测试。这种重构会花费开发时间,但您的代码会变得更干净、更安全。

相反,如果您拒绝重构代码,您可以“按原样”运行测试的唯一方法是在调用 JVM 时设置 System 属性值:

java -DMyField=... foo.bar.MyTest

【讨论】:

  • 谢谢,这似乎可以解释问题。我会考虑将我的字段更改为变量。
【解决方案2】:

类加载时初始化的静态字段。 JVM加载类,然后你设置系统属性,但是类已经加载并且静态字段初始化为null,因为在类加载时属性是空的......

【讨论】:

    猜你喜欢
    • 2011-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-12
    • 2021-10-04
    • 1970-01-01
    • 2014-10-06
    • 1970-01-01
    相关资源
    最近更新 更多