@BeforeClass vs static {}

我正在使用JUnit编写一些测试用例。 我需要初始化一些静态变量,这些变量将用于该类中的所有测试用例。

为此我可以使用其中之一

  1. 静态初始化程序块或
  2. 使用@BeforeClass静态方法

使用一个在另一个上有什么好处?

@BeforeClassstatic初始化程序有很多不同的语义。

静态初始化程序由JVM调用,而不是由JUnit调用。 如果在静态初始化程序中抛出exception,则测试框架可能无法捕获并报告exception。 此外,与@BeforeClass方法相比,静态初始化程序的调用时间没有明确定义。 它在第一次实际使用时 每个类加载器只运行一次 ,例如访问静态属性,静态方法或其构造函数之一。 有时,可能很难弄清楚这是什么时候。 (如果你不使用inheritance:你可能有一天或某个同事会重构你的测试用例。如果不是今天,选择静态初始化器可能会在将来引入令人讨厌的错误。)

另一方面,在运行每个类的测试之前运行@BeforeClass 。 如果一个类会受到不同的测试,例如由于inheritance构建的测试, static初始化程序将仅使用此类运行第一次测试。 这意味着您使测试订单依赖于您从未想要的东西。

请注意,两个选项之间的语义差异大于使用@Before或测试的构造函数之间的语义差异。 作为最后的论点,考虑一下注释的纪录价值。 它使您的意图更具可读性。

此规则的唯一例外是不可变常量。 这些应该在他们的声明中初始化,以保持你的代码简洁,并尊重编译时常量 。 如果您的值是可变的,则根本不应使用static值。 同样,在测试中更改的可变值会为您的测试引入顺序依赖性,这是应该避免的。

TL; DR:使用@BeforeClass

在决定是使用静态初始化块还是@BeforeClass时,可以考虑以下几个注意事项:

  1. @BeforeClass@AfterClass的对手。 因此,如果您进行需要稍后清理的初始化(比如打开外部资源),那么使用带注释的方法会更好(从语义的角度来看)。
  2. 如果执行可能抛出已检查exception的复杂初始化,则使用@BeforeClass会更加舒适,因为您不必捕获并将其包装到未经检查的exception中。
  3. 如果要使用具有复杂初始化的常量语义 ( private static final String VARIABLE ),则除了使用静态初始化块或静态方法之外别无选择。

在SO上有一个相关的post: unit testing – 使用@BeforeClass和在JUnit 4 Java中使用实例或静态变量有什么区别?

如果它既是static又是final那么你只有一个选择:静态初始化器。

编译器将阻止您从方法内部写入最终字段,静态或不静态。

编辑:好的,你已从你的问题中删除了“最终”这个词。 在这种情况下,它没什么区别。 静态初始化程序将运行一次; @BeforeClass方法也是如此。 只需选择您认为更具可读性的那个。

这不是完全相同的行为。 @BeforeClass在每次运行测试时运行,静态初始化程序仅在加载类时运行一次。 如果你的testrunner使用相同的类加载器,那么在@BeforeClass的情况下,你将重新运行静态变量的初始化。 这取决于你想在这里实现的目标。