重置JUnit测试的静态字段

The*_*son 9 java junit

我有一组JUnit测试,它们在Java程序上调用main方法,传入args并检查输出.没关系.

但是,如果我测试的程序具有被更改的静态值,则它们在测试之间将保持不变.这会导致问题.我无法控制正在测试的程序是什么,或者用于静态字段的名称.

我如何确保我的单元测试运行干净,就好像它是从头开始程序,而不保留那些静态字段.有没有办法以某种方式重置它们?

如果没有,我将不得不启动一个运行该程序的新进程,然后检查输出等,但这似乎有点矫枉过正.

编辑 - 请注意我无法控制单元测试正在测试的代码 - 我无法更改其字段名称,不幸的是,我也不会知道他们的字段名称.我想,如果没有开始新的流程,这是不可能的?

Joe*_*oel 7

你应该明确地初始化你的测试类中的任何静止的状态,通常这是在注释的方法完成@Before@BeforeClass

这是一个原因,其中包括为什么在应用程序中拥有大量静态依赖项是一个不好的测试想法.这就是为什么许多人鼓励无国籍编程.


Zer*_*One 5

一般来说,如果您发现您的代码无法测试,就像这里的问题一样,这是代码异味的迹象,您应该认真考虑重构您的代码以不使用这些静态字段。

话虽如此,您可能会发现BeanInject 库很有帮助。您可以将一个带@After注释的方法放入您的测试类中,并使用注入重置静态字段:

Inject.field("thatStaticField").of(thatObjectWithStaticFields).with("default value");
Run Code Online (Sandbox Code Playgroud)

这样你只需要知道字段名称,但你不必能够实际修改带有字段的类。图书馆使用反射来做到这一点。

此外,我想到如果您正在测试包含您无法控制的部分的东西,为什么不尝试使用 Mockito 来模拟这些部分?

编辑/添加:好的,所以您的问题是您甚至不知道类可能具有或不具有的可能静态变量的初始值。我看到两种可能的方法:1) 您必须在第一次加载类时保存它们的值并在每次测试之间重置值,或者 2) 您必须从类加载器。

在第 1) 点上,您需要使用反射循环遍历 @BeforeClass 方法中的所有字段,将它们的初始值保存到某个Map<String,Object>结构中,然后重置 @Before 或 @After 方法中的值。这里有一些关于使用反射循环遍历类的字段的主题:循环遍历 Java 类中的所有字段

关于第 2 点),您在此处有相关说明(涉及类加载器):Java:如何“重新启动”静态类?

你可以用反射和那些东西做的事情很酷。:)


Joh*_*n B 5

看一下这篇文章:设置私有静态字段。与 BeanInject 或ReflectionTestUtils(我经常使用它们)不同,此机制不需要类的实例。由于这是一个静态字段,我不确定您是否有一个实例。如果这样做,请使用上述两者之一。

从帖子中复制:

 public static void main(String[] args) throws Exception
{
    Field field = MyClass.class.getDeclaredField("woot");
    field.setAccessible(true);
    field.set(null, "New value");
}
Run Code Online (Sandbox Code Playgroud)

我很惊讶地发现这ReflectionTestUtils需要一个实例。看起来应该能够处理这种情况。太糟糕了。

正如其他人所说,在@Before方法中执行此操作以确保测试开始之前的状态。这样做@After很容易出错,因为它假设您的其他测试可能会影响静态字段的状态。