【问题标题】:JUnit classloader issues when moving to Maven with System properties and static fields使用系统属性和静态字段迁移到 Maven 时出现 JUnit 类加载器问题
【发布时间】:2016-05-26 16:57:39
【问题描述】:

我正在努力将我们的旧版本从使用 Ant 转换为 Maven(3.3.3,如果重要的话),但遇到了障碍。我们的代码库有一个从系统属性初始化私有静态字段的类,这些属性通常由应用程序调用时的启动脚本填充。执行此代码的单元测试是在执行测试之前设置系统属性。在 Ant 中或通过 Eclipse JUnit 运行器运行单元测试时,一切正常。通过maven运行时,似乎在单元测试执行之前就初始化了静态字段,导致属性不存在,测试失败。

我已经整理了一个示例类和单元测试来演示,因为我不允许在这里发布实际代码。

package foo.bar;

public class ValueClass { 
    private static final String SAMPLE_FIELD = "Foo " + System.getProperty("target.value");

    private final myValueField;

    public ValueClass() {
        myValueField = "random text " + SAMPLE_FIELD;
    }

    public String getValueField() { 
        return myValueField;
    }
}

以及对应的单元测试:

package foo.bar;

import org.junit.Test;
import org.junit.BeforeClass;

public class ValueClassTest { 

    @BeforeClass
    public static void setupBeforeClasses() { 
        System.setProperty("target.value", "value from test");
    }

    @Test
    public void testGetValueField() { 
        String expected = "random text Foo value from test";

        ValuesClass valuesClassInstance = new ValuesClass();

        String actual = valuesClassInstance.getValueField();

        assertEquals(expected, actual);
    }  
}

正如我所提到的,当我使用 Ant 或 Eclipse 执行时,一切正常。我玩过一些日志记录(将一些日志消息放到 ValueClass 中的静态块中),并确定在 Eclipse 或 Ant 中运行时,在 testGetValueField 方法执行期间加载了该类,而在 Maven 中,加载了该类在 setupBeforeClasses 方法执行之前的某个时间。这会导致 SAMPLE_FIELD 使用来自“target.value”系统属性的空值进行初始化。

非常感谢任何帮助! 抢

【问题讨论】:

  • 刚用 Maven 试过这个...效果很好。
  • 也适用于 IntelliJ...不管是什么导致了这个问题,它似乎不是 Maven...也许清理你的 pom,一些插件可能在你的测试运行之前实例化类?跨度>
  • 这是个好主意...我将在其他测试中使用 ValueClass 搜索其他任何内容。当我通过 Eclipse 在独立模式下对其进行测试时,我只执行了一个类。
  • 果然有另一个类在前面执行的测试中引用了ValueClass。
  • 除非您确保没有任何其他测试或在此测试运行之前执行的代码对此 ValueClass 进行引用,否则该类将在您的 @BeforeClass 方法运行之前由 JVM 创建。这几乎不可能可靠地工作。从 pom 或在任何测试开始之前运行的东西设置系统属性,并记住测试之间不应该有顺序。

标签: java maven junit classloader


【解决方案1】:

如果您可以从pom.xml 设置系统属性,则停止从@BeforeClass 方法和try this 进行设置:

<project>
        [...]
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.19.1</version>
        <configuration>
          <systemPropertyVariables>
            <propertyName>propertyValue</propertyName>
            <buildDirectory>${project.build.directory}</buildDirectory>
            [...]
          </systemPropertyVariables>
        </configuration>
      </plugin>
    </plugins>
  </build>
        [...]
</project>

【讨论】:

  • 那行得通...为了保持对在 Eclipse 中执行测试的支持,我需要保留原来的 setupBeforeClasses 方法,复制这两个场景的初始化。我会继续前进,并对此发表评论。在相关的说明中,您知道为什么这两种类加载器类型的行为会有所不同吗?
  • 根据上述评论的建议,我查看了测试的执行顺序,并且有一个不同的测试引用了 ValueClass。而不是类加载器不同(这很可怕),单元测试只是以不同的顺序执行(这远没有那么可怕)。
  • 偶然在 Eclipse 中工作...只是碰巧测试运行的顺序是它使事情正常运行...除非您分叉每个测试,您可以从 Maven 和 Eclipse 中完成,但是每次测试都启动 JVM 的成本很高,所以你应该尽量避免这种情况。
  • 顺便说一句,这不是类加载器问题。 JVM 类加载器需要在第一次使用时实例化类,所以据我所知,在任何 JVM 中行为都是完全相同的......
猜你喜欢
  • 2016-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-25
  • 1970-01-01
  • 1970-01-01
  • 2011-09-12
  • 1970-01-01
相关资源
最近更新 更多