Как я могу заставить JUnit 4.8 запускать код после неудачного теста, но перед любыми методами @After?

Я запускаю набор тестов Selenium (фактически Selenium, поддерживаемый WebDriver), используя JUnit 4.8.2. Я бы хотел, чтобы тесты автоматически делали снимок экрана браузера, как только тест терпит неудачу. Все тесты наследуются от SeleniumBaseTestCase, а большинство затем наследуются от SeleniumBastTestCaseWithCompany (который использует методы @Before и @After для создания и последующей очистки общих тестовых данных через Selenium).

Я попытался добавить подкласс TestWatchman в качестве @Rule в SeleniumBaseTestCase, переопределив метод failed TestWatchman, чтобы сделать снимок экрана. Проблема в том, что методы @After, очищающие тестовые данные, запускаются до вызова метода failed TestWatchman, поэтому все скриншоты — это последний шаг очистки, а не тест, который не прошел.

Присмотревшись немного, кажется, что метод apply TestWatchman просто вызывает переданный метод оценки Statement (единственный доступный метод), который вызывает методы @After, не оставляя TestWatchman (или любому другому Rule) возможности вставить какой-либо код между выполнением тест и методы @After, насколько я могу судить.

Я также видел подходы, которые создают пользовательский Runner для изменения созданных Statement, чтобы методы, аннотированные пользовательским @AfterFailure, запускались перед методами @After (поэтому скриншот можно сделать в таком методе @AfterFailure), но это зависит от переопределения BlockJUnit4ClassRunner withAfters. метод, который устарел и должен стать частным, согласно документация, в которой вместо этого предлагается использовать правила.

Я нашел еще один ответ на SO о жизненном цикле @Rule, который делает его звучит так, будто это просто невозможно в JUnit 4.8, но возможно в JUnit 4.10. Если это так, то достаточно честно, я просто хотел бы сначала подтвердить это.

Любые мысли об элегантном и ориентированном на будущее способе, с помощью которого я могу достичь того, чего хочу, будут высоко оценены!


person Rowan    schedule 19.12.2011    source источник


Ответы (1)


Вы правы в своем анализе, @Befores и @Afters добавляются в список утверждений перед любыми правилами. @Before выполняется после @Rule, а @After выполняется до @Rule. То, как вы это исправите, зависит от того, насколько гибкими вы можете быть с SeleniumBaseTestCaseWithCompany.

Самый простой способ — удалить ваши @Before/@After методы и заменить их ExternalResource. Это может выглядеть примерно так:

public class BeforeAfterTest {
    @Rule public TestRule rule = new ExternalResource() {
        protected void before() throws Throwable { System.out.println("externalResource before"); }
        protected void after() { System.out.println("externalResource after"); }
    };

    @Test public void testHere() { System.out.println("testHere"); }
}

это дает:

externalResource before
testHere
externalResource after

Это поле можно поместить в ваш базовый класс, чтобы оно наследовалось/переопределялось. Ваша проблема с упорядочением между @After и вашими правилами исчезнет, ​​потому что вы можете упорядочить свои правила так, как вам нравится, используя @RuleChain (в версии 4.10, а не 4.8).

Если вы не можете изменить SeleniumBaseTestCaseWithCompany, вы можете расширить BlockJUnit4ClassRunner, но не переопределять withAfters, а переопределять BlockJUnit4ClassRunner#methodBlock(). Затем вы можете вызвать super.methodBlock и изменить порядок утверждений по мере необходимости [*].

[*]Вы можете просто скопировать код и изменить порядок строк, но withRules является приватным и, следовательно, не может быть вызван из подкласса.

person Matthew Farwell    schedule 20.12.2011
comment
Да, я думаю, что обновление JUnit - это путь - я не вижу особенно удовлетворительного решения в 4.8.2. У меня есть защищенный TestWatcher на SeleniumBaseTestCase, чтобы делать скриншоты, и RuleChain с единственным правилом. Затем в SeleniumBaseTestCaseWithCompany у меня есть ExternalResource для создания/удаления компании, и я затеняю RuleChain суперкласса, упорядочивая как скриншот, так и правило создания/удаления. Кажется, работает хорошо, спасибо. - person Rowan; 21.12.2011
comment
Просто заметка. В версии 4.11 вы сможете указать @Rule для метода, чтобы вы могли переопределить этот метод, а не затенять поле. Но 4.11 еще не вышла. - person Matthew Farwell; 21.12.2011