重置JUnit测试的静态字段

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

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

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

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

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

一般来说,如果你发现你的代码是不可测试的,就像这里的问题一样,它是代码味道的标志,你应该认真考虑重构代码以不使用那些静态字段。

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

 Inject.field("thatStaticField").of(thatObjectWithStaticFields).with("default value"); 

这样,您只需要知道字段名称,但您不必能够使用字段实际修改类。 该库使用reflection来做到这一点。

另外,我想到,如果你正在测试包含你无法控制的部分的东西,你为什么不试着用Mockito来模仿这些部分呢?

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

在第1点),您需要使用reflection循环遍历@BeforeClass方法中的所有字段,将其初始值保存到某个Map结构中,然后重置@Before或@After中的值方法。 以下是使用reflection循环遍历类的字段的一些主题: 循环遍历Java类中的所有字段

关于第2点),你有这方面的指示(涉及类加载器): Java:如何“重启”一个静态类?

你可以用reflection和那些东西做很酷的事情。 🙂

您应该在测试类中显式初始化任何静态,通常这是在注释@Before@BeforeClass方法中完成的

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

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

复制自post:

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

我很惊讶地看到ReflectionTestUtils需要一个实例。 似乎它应该能够处理这种情况。 太糟糕了。

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