首页 > 解决方案 > 使用来自系统属性的静态最终字段进行单元测试

问题描述

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

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);
            ...
        }
     }
}

标签: javajunit

解决方案


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

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

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

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

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

推荐阅读