Я создал класс с парой тестов, и вместо использования @Beforeя хотел бы иметь метод настройки, который выполняется только один раз перед всеми тестами. Возможно ли это с Junit 4.8?
Хотя я согласен с @assylias, что использование @BeforeClass- классическое решение, оно не всегда удобно. Метод, помеченный значком, @BeforeClassдолжен быть статическим. Это очень неудобно для некоторых тестов, которым нужен экземпляр тестового примера. Например, тесты на основе Spring, которые используются @Autowiredдля работы со службами, определенными в контексте Spring .
В этом случае я лично использую обычный setUp()метод, аннотированный @Beforeаннотацией, и управляю своим настраиваемым static(!) booleanФлагом:
privatestaticboolean setUpIsDone =false;.....@Beforepublicvoid setUp(){if(setUpIsDone){return;}// do the setup
setUpIsDone =true;}
Добавление к комментарию Кенни Кейсона о том, почему он должен быть статичным. Он должен быть статическим, потому что JUnit создает новый экземпляр тестового класса для каждого метода @Test. Переменная экземпляра будет сброшена на значение по умолчанию (false) для каждого экземпляра, если оно не статично. См. Дополнительную информацию: martinfowler.com/bliki/JunitNewInstance.html
dustin.schultz
2
Это работает, за исключением случая, когда setUp()метод находится в суперклассе - ниже был опубликован ответ, пытающийся решить эту проблему.
Стив Чемберс,
4
Я не решаюсь сказать это кому-нибудь с репутацией в 84 тыс., Но BeforeClass фактически не отвечает на вопрос: BeforeClass запускается в начале каждого тестового класса. Но OP попросил тот, который запускается «только один раз перед всеми тестами». Предлагаемое вами решение могло бы сделать это, но вам нужно было бы сделать так, чтобы все ваши тестовые классы расширяли класс "CommonTest" ...
Майк грызун
1
@mikerodent, IMHO OP спросил обо всех тестах в его тестовом примере, а не обо всех тестах в целом. Итак, ваш комментарий менее актуален. Кстати, не бойтесь говорить что-либо любому человеку, даже если у него высокая репутация. По крайней мере, я так делаю :). И моя репутация была значительно ниже в августе 2012 года, когда я ответил на вопрос.
AlexR
В моем случае не работает, переменные, инициализированные в настройке, сбрасываются после каждого теста, поэтому запускать только один раз бессмысленно.
@mikerodent Я понял вопрос как «все тесты в классе» - но вы правы, это может быть не то, что хотел OP.
assylias
29
JUnit 5 теперь имеет аннотацию @BeforeAll:
Обозначает, что аннотированный метод должен выполняться перед всеми методами @Test в текущем классе или иерархии классов; аналогично @BeforeClass из JUnit 4. Такие методы должны быть статическими.
Аннотации жизненного цикла JUnit 5, похоже, наконец-то все поняли! Вы можете догадаться, какие аннотации доступны, даже не глядя (например, @BeforeEach @AfterAll)
У него та же проблема @BeforeClass, что и должна быть static. Решение IMO @ AlexR лучше.
zengr
@zengr склонен согласиться с вами: как я сказал AlexR, его решение требует, чтобы все тестовые классы были подклассами от класса CommonTest, если он должен запускаться только один раз. Но это настолько просто, насколько это возможно, и ИМХО вам, вероятно, не следует использовать "модное" решение, поставляемое фреймворком, когда простой механизм доступен из языка. Если, конечно, нет на то веской причины. Кроме того, использование такой простой вещи, как его, с хорошим названием типа «делает то, что написано на жестяной коробке», помогает улучшить читаемость.
Майк грызун
Сказав это, опять же ИМХО, кажется, гораздо больше оправданий для аннотации «AfterAll»: было бы очень сложно и надумано разработать механизм для определения того, когда все тесты были выполнены. И наоборот, конечно, пуристы, вероятно, скажут, что вам никогда не следует делать «окончательную очистку», т.е. что каждый «tearDown» должен оставлять все ресурсы в первозданном состоянии ... и они, вероятно, правы!
Майк грызун
Работает ли это с Maven, где есть несколько модулей, каждый со своими тестами?
Марк Бун
@mike rodent, в моем случае установка и удаление тестовых файлов в файловой системе до / после каждого теста, похоже, приводит к тупикам в файлах. На данный момент я самостоятельно пришел к решению AlexR по настройке один раз. У меня есть два статических флага, уже установленный и грязный. setup () вызывает cleanup (), если изначально обнаружено «грязное» состояние или если сбой установки приводит к «грязному» состоянию. Чтобы очистить после запуска тестов, я запускаю их снова. Грязный, совсем не идеальный, не в нашем процессе сборки. Все еще ищу способ получше (jUnit 4.12).
Ребекка
9
Когда он setUp()находится в суперклассе тестового класса (например, AbstractTestBaseниже), принятый ответ можно изменить следующим образом:
publicabstractclassAbstractTestBase{privatestaticClass<?extendsAbstractTestBase> testClass;.....publicvoid setUp(){if(this.getClass().equals(testClass)){return;}// do the setup - once per concrete test class.....
testClass =this.getClass();}}
Это должно сработать для одного нестатического setUp()метода, но я не могу создать его эквивалент, tearDown()не попадая в мир сложных отражений ... Награда указывает всем, кто может!
Изменить:
я только что узнал при отладке, что класс также создается перед каждым тестом. Думаю, аннотация @BeforeClass здесь лучше всего.
Вы также можете настроить конструктор, в конце концов , тестовый класс - это класс. Я не уверен, что это плохая практика, потому что почти все другие методы аннотированы, но это работает. Вы можете создать такой конструктор:
public UT (){// initialize once here}@Test// Some test here...
Ctor будет вызываться перед тестами, потому что они не статичны.
с аннотацией @BeforeAllMethods/ @AfterAllMethodsвы можете выполнить любой метод в классе Test в контексте экземпляра, где доступны все введенные значения.
открытый класс TestCaseExtended расширяет TestCase {частное статическое логическое значение isInitialized = false; частный статический TestCaseExtended caseExtended; частный int serId; @Override public void setUp () выдает исключение {super.setUp (); если (! isInitialized) {caseExtended = новый TestCaseExtended (); caseExtended.loadSaveNewSerId (); caseExtended.emptyTestResultsDirectory (); isInitialized = true; }}
Оби Два
0
Если вы не хотите принудительно объявлять переменную, которая устанавливается и проверяется в каждом подтесте, тогда добавление этого в SuperTest может сделать:
Добавьте в свой базовый абстрактный класс (я имею в виду абстрактный класс, в котором вы инициализируете свой драйвер в методе setUpDriver () ) эту часть кода:
privatestaticboolean started =false;static{if(!started){
started =true;try{
setUpDriver();//method where you initialize your driver}catch(MalformedURLException e){}}}
И теперь, если ваши тестовые классы будут расширяться от базового абстрактного класса -> метод setUpDriver () будет выполняться перед первым @Test только ОДИН раз за запуск.
Ответы:
Хотя я согласен с @assylias, что использование
@BeforeClass
- классическое решение, оно не всегда удобно. Метод, помеченный значком,@BeforeClass
должен быть статическим. Это очень неудобно для некоторых тестов, которым нужен экземпляр тестового примера. Например, тесты на основе Spring, которые используются@Autowired
для работы со службами, определенными в контексте Spring .В этом случае я лично использую обычный
setUp()
метод, аннотированный@Before
аннотацией, и управляю своим настраиваемымstatic
(!)boolean
Флагом:источник
setUp()
метод находится в суперклассе - ниже был опубликован ответ, пытающийся решить эту проблему.Вы можете использовать в
BeforeClass
аннотации :источник
TheClassYouWant.class
вместо вызова getClass ()? Это актуально Java:String.class.getName()
.JUnit 5 теперь имеет аннотацию @BeforeAll:
Аннотации жизненного цикла JUnit 5, похоже, наконец-то все поняли! Вы можете догадаться, какие аннотации доступны, даже не глядя (например, @BeforeEach @AfterAll)
источник
@BeforeClass
, что и должна бытьstatic
. Решение IMO @ AlexR лучше.Когда он
setUp()
находится в суперклассе тестового класса (например,AbstractTestBase
ниже), принятый ответ можно изменить следующим образом:Это должно сработать для одного нестатического
setUp()
метода, но я не могу создать его эквивалент,tearDown()
не попадая в мир сложных отражений ... Награда указывает всем, кто может!источник
Изменить: я только что узнал при отладке, что класс также создается перед каждым тестом. Думаю, аннотация @BeforeClass здесь лучше всего.
Вы также можете настроить конструктор, в конце концов , тестовый класс - это класс. Я не уверен, что это плохая практика, потому что почти все другие методы аннотированы, но это работает. Вы можете создать такой конструктор:
Ctor будет вызываться перед тестами, потому что они не статичны.
источник
Попробуйте это решение: https://stackoverflow.com/a/46274919/907576 :
с аннотацией
@BeforeAllMethods
/@AfterAllMethods
вы можете выполнить любой метод в классе Test в контексте экземпляра, где доступны все введенные значения.источник
Мое грязное решение:
Я использую его как базу для всех своих тестов.
источник
Если вы не хотите принудительно объявлять переменную, которая устанавливается и проверяется в каждом подтесте, тогда добавление этого в SuperTest может сделать:
источник
Я решил эту проблему так:
Добавьте в свой базовый абстрактный класс (я имею в виду абстрактный класс, в котором вы инициализируете свой драйвер в методе setUpDriver () ) эту часть кода:
И теперь, если ваши тестовые классы будут расширяться от базового абстрактного класса -> метод setUpDriver () будет выполняться перед первым @Test только ОДИН раз за запуск.
источник
Используйте метод Spring @PostConstruct для выполнения всей работы по инициализации, и этот метод запускается до выполнения любого из @Test.
источник