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

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

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

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

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

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

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

Ответ 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 является приватным и, следовательно, не может быть вызван из подкласса.