简体   繁体   中英

@BeforeClass vs static{}

I am writing some test cases using JUnit. I need to initialize some static variables which will be used for all the test cases in that class.

For this I can use either

  1. Static initializer block or
  2. Static method with @BeforeClass

What are the advantages of using one over another?

There are very different semantics for @BeforeClass or a static initializer.

A static initializer is invoked by the JVM and not by JUnit. If an exception is thrown within a static initializer, the test framework might not be able to catch and report the exception. Furthermore, the invocation time of the static initializer is not well-defined compared to the @BeforeClass method. It will be run only once per class loader on its first actual use which is for example the access of a static property, a static method or one of its constructors. Sometimes, it might be hard to figure out when this will be. (If you do not use inheritence: You might one day or some coworker will refactor your test case. If not today, the choice for a static initializer might introduce nasty bugs in the future.)

On the other hand, @BeforeClass is run before each class's tests are run. If a class would be subject to different tests, for example due to tests built on inheritance, the static initializer will only run for the first test using this class. This means that you made your test order dependent what is something you never want.

Note that the semantic difference between the two options is bigger than between using @Before or a constructor for a test. As a final argument, think about the documentary value of the annotations. It makes your intentions more readable.

The only exception for this rule would be immutable constants. Those should be initialized within their declaration in order to keep your code concise and in order to respect compile time constants . If your values are however mutable, you should not use static values at all. Again, mutable values that are altered in a test introduce an order dependency to your test which is to be avoided.

TL;DR: Use @BeforeClass !

Here's a couple of considerations that could be taken into account when deciding whether to use the static initialization block or @BeforeClass :

  1. @BeforeClass is the antagonist of @AfterClass . So if you do initializations that require cleaning up later (like opening external resources) it would be better (from a semantic point of view) to use the annotated methods.
  2. If you do complex initializations that might throw checked exceptions it's much more comfortable to use @BeforeClass , because you don't have to catch and wrap it into an unchecked exception.
  3. If you want to use constant semantics ( private static final String VARIABLE ) with complex initialization, you will have no choice but to use the static initialization block or a static method.

There is a related post on SO: unit testing - What's the difference between using @BeforeClass and using instance or static variable in JUnit 4 Java?

If it's both static and final then you only have one choice: static initializer.

The compiler will prevent you from writing to a final field from inside a method, static or not.

EDIT: OK, you've removed the word 'final' from your question. In that case, it makes little difference. The static initializer will run once; so will the @BeforeClass method. Just pick whichever one you think is more readable.

It's not exactly the same behavior. @BeforeClass runs everytime the tests are run, a static initializer only once when the class is loaded. If your testrunner uses the same classloader, then in the case of @BeforeClass , you would re-run the initialization of the static variable. It depends on what you want to achieve here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM