@BeforeClass vs static {}

Я пишу несколько тестовых примеров с помощью JUnit. Мне нужно инициализировать некоторые статические переменные, которые будут использоваться для всех тестовых случаев в этом классе.

Для этого я могу использовать либо

  • Статический блок инициализатора или
  • Статический метод с @BeforeClass

В чем преимущества использования одного над другим?

Ответ 1

Для семантики @BeforeClass или static существует очень разная семантика.

Статический инициализатор вызывается JVM, а не JUnit. Если в статическом инициализаторе выбрано исключение, тестовая структура может быть неспособна поймать и сообщить об исключении. Кроме того, время вызова статического инициализатора не является корректным по сравнению с методом @BeforeClass. Он будет выполняться только один раз для загрузчика классов при его первом действительном использовании, например, доступ к статическому свойству, статическому методу или одному из его конструкторов. Иногда бывает сложно определить, когда это будет. (Если вы не используете наследование: однажды вы или кто-то из коллег реорганизует ваш тестовый пример. Если не сегодня, выбор для статического инициализатора может привести к неприятным ошибкам в будущем.)

С другой стороны, @BeforeClass запускается до запуска каждого теста класса. Если класс будет подвергаться различным испытаниям, например, из-за тестов, построенных на наследовании, инициализатор static будет запускаться только для первого теста с использованием этого класса. Это означает, что вы сделали свой тестовый заказ зависимым от того, чего вы никогда не хотите.

Обратите внимание, что семантическая разница между двумя параметрами больше, чем между использованием @Before или конструктором для теста. В качестве последнего аргумента, подумайте о документальной стоимости аннотаций. Это делает ваши намерения более читабельными.

Единственное исключение для этого правила было бы неизменяемыми константами. Они должны быть инициализированы в рамках их декларации, чтобы сохранить код коротким и соблюдать константы времени компиляции. Если ваши значения изменяются, вы не должны использовать значения static вообще. Опять же, изменяемые значения, измененные в тесте, вводят зависимость от вашего теста, которую следует избегать.

TL; DR: используйте @BeforeClass!

Ответ 2

Вот несколько соображений, которые могут быть приняты во внимание при принятии решения о том, следует ли использовать статический блок инициализации или @BeforeClass:

  • @BeforeClass является антагонистом @AfterClass. Поэтому, если вы выполняете инициализацию, требующую очистки позже (например, открытие внешних ресурсов), было бы лучше (с семантической точки зрения) использовать аннотированные методы.
  • Если вы выполняете сложные инициализации, которые могут выдавать проверенные исключения, гораздо удобнее использовать @BeforeClass, потому что вам не нужно ловить и обернуть его в неконтролируемое исключение.
  • Если вы хотите использовать константную семантику (private static final String VARIABLE) со сложной инициализацией, у вас не останется выбора, кроме как использовать статическую инициализацию блок или статический метод.

Существует ссылка на SO: unit testing - Какая разница между использованием @BeforeClass и использованием экземпляра или статической переменной в JUnit 4 Java?

Ответ 3

Если это и static и final, тогда у вас будет только один выбор: статический инициализатор.

Компилятор запретит вам писать в конечное поле внутри метода, статическим или нет.

EDIT: ОК, вы удалили слово "final" из своего вопроса. В этом случае это мало чем отличается. Статический инициализатор будет запускаться один раз; так будет и метод @BeforeClass. Просто выберите то, что вы считаете более читаемым.

Ответ 4

Это не совсем то же самое поведение. @BeforeClass запускается каждый раз при запуске тестов, статический инициализатор только один раз, когда класс загружается. Если ваш testrunner использует один и тот же загрузчик классов, то в случае @BeforeClass вы должны повторно запустить инициализацию статической переменной. Это зависит от того, чего вы хотите достичь здесь.