Примените "@Rule" после каждого "@Test" и перед каждым "@After" в JUnit

У меня есть набор тестов, в котором я выхожу из системы в @After и закрываю браузер в @AfterClass. Я пытаюсь использовать @Rule, чтобы выполнить неудачный скриншот с использованием Selenium для каждого тестового метода. Я вручную проверил, что @Rule работает только перед каждым @Before, но я хочу настроить его после @Test и до @After. Я не мог найти простого решения. Любая помощь будет оценена.

public class MorgatgeCalculatorTest  {

@Before
public void before(){
    System.out.println("I am before");
}
@BeforeClass
public static void beforeclass(){
    System.out.println("I am beforeclass");
}
@Test
    public void test(){
        System.out.println("I am Test");
    }
@Test
public void test2(){
    System.out.println("I am Test2");
}
@After
    public void after(){
        System.out.println("I am after");
    }
@AfterClass
        public static  void afterclass(){
            System.out.println("I am afterclass");

}
@Rule
ExpensiveExternalResource ExpensiveExternalResource = new ExpensiveExternalResource();

static class ExpensiveExternalResource implements MethodRule  {
    public ExpensiveExternalResource(){
        System.out.println("I am rule");
    }

    @Override
    public Statement apply(Statement arg0, FrameworkMethod arg1, Object arg2) {
        // TODO Auto-generated method stub
        return null;
    }    
}               

Выход, который я получаю,

I am beforeclass
I am rule
I am before
I am Test
I am after
I am rule
I am before
I am Test2
I am after
I am afterclass

Ответы

Ответ 1

Из-за того, что правила настроены, вы не можете иметь правило, которое появляется после @раньше или до @после. Вы можете думать о правилах, таких как оболочки, которые вы накладываете на метод тестирования. Первая оболочка для продолжения - @перед/@после. После этого применяются @rules.

Быстрый способ сделать то, что вы хотите сделать, это избегать @После всех вместе. Правило может быть создано таким образом, чтобы он выполнял скриншот, если метод завершился неудачей, а затем выполните ваш код. Это не так красиво, как @After, но это работает. (также я внедрил TestRule, потому что MethodRule был обесценен).

public class MorgatgeCalculatorTest  {
    @Before
    public void before(){
        System.out.println("I am before");
    }

    @BeforeClass
    public static void beforeclass(){
        System.out.println("I am beforeclass");
    }

    @Test
    public void test(){
        System.out.println("I am a Test");
    }

    @Test
    public void test2(){
        System.out.println("I am a Failed Test");
        fail();
    }

    @AfterClass
            public static  void afterclass(){
                System.out.println("I am afterclass");

    }

    @Rule
    public ExpensiveExternalResource ExpensiveExternalResource = new ExpensiveExternalResource();

    public static class ExpensiveExternalResource implements TestRule  {


      //  public ExpensiveExternalResource(){}


        public class ExpansiveExternalResourceStatement extends Statement{

            private Statement baseStatement;

            public ExpansiveExternalResourceStatement(Statement b){
                baseStatement = b;
            }

            @Override
            public void evaluate() throws Throwable {
                try{
                    baseStatement.evaluate();
                }catch(Error e){
                    System.out.println("I take a Screenshot");
                    throw e;   
                }finally{
                    after();
                }
            }

            //Put your after code in this method!
            public void after(){
                System.out.println("I am after");
            }
        }

        public Statement apply(Statement base, Description description) {
            return new ExpansiveExternalResourceStatement(base);

        }


    }
}

Вся работа правила выполняется в инструкции. Org.junit.runners.model.Statement - это класс, представляющий собой набор кода. Таким образом, здесь метод apply получает пакет кода, в который вы помещаете оболочку. Apply возвращает ваш оператор, который выполняет комплект кода, который вы ему дали, и окружает его с помощью инструкции try/catch, чтобы поймать ошибки метода.

Выход для этого метода:

I am beforeclass
I am before
I am a Test
I am after
I am before
I am a Failed Test
I take a Screenshot
I am after
I am afterclass

Надеюсь, это поможет!

Ответ 2

public class ScreenshotTestRule implements MethodRule {
    public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object o) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                try {
                    statement.evaluate();

                } catch (Throwable t) {
                    captureScreenshot(frameworkMethod.getName());
                    throw t; // rethrow to allow the failure to be reported to JUnit                     
                } finally {
                    tearDown();
                }
            }

            public void tearDown() {
                //logout to the system;
            }


            public void captureScreenshot(String fileName) {
                try {
                    new File("target/surefire-reports/screenshot").mkdirs(); // Insure directory is there
                    FileOutputStream out = new FileOutputStream("target/surefire-reports/screenshot/screenshot-" + fileName + ".png");
                    out.write(((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES));
                    out.close();
                } catch (Exception e) {
                    // No need to crash the tests if the screenshot fails
                }
            }
        };
    }
}

Ответ 3

Как насчет использования правила ExternalResource?
Похоже, вы можете дать вам достаточно гибкости для того, что вам нужно.
И если это не совсем то, что вам нужно, ознакомьтесь с исходным кодом внешнего ресурса.
Это довольно понятно, как реализовать правило, например, которое будет работать только после вызова теста.