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

у меня есть набор тестов, где я выхожу из системы в @After и закрытие браузера в @AfterClass. Я пытаюсь использовать @Rule принять неудачный скриншот теста с использованием Селена для каждого метода тестирования. Я проверил вручную, что @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

3 ответов


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

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

public class MortgageCalculatorTest  {
    @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);

        }


    }
}

вся работа правила выполняется в инструкции. Орг.тесты JUnit.бегуны.модель.Оператор-это класс, представляющий собой пакет кода. Так вот применить метод получает пакет кода,который вы помещаете в оболочку. 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

надеюсь, что это помогает!


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
                }
            }
        };
    }
}

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