Apply '@Rule' after each '@Test' and before each '@After' in JUnit Apply '@Rule' after each '@Test' and before each '@After' in JUnit selenium selenium

Apply '@Rule' after each '@Test' and before each '@After' in JUnit


Because of the way that rules are set up, you can't have a rule that comes after @before or before @after. You can think of rules like shells that you put on the test method. The first shell to go on is @before/@after. Thereafter the @rules are applied.

A quick way to do what you want to do is to avoid @After altogether. A rule can be created so that it will take a screenshot if a method fails and then execute yours after the code. It isn't quite as pretty as @After, but it works. (also I implemented TestRule because MethodRule has been depreciated).

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

All the work of the rule is done in a statement. A org.junit.runners.model.Statement is a class that represents a bundle of code. So here the apply method receives the bundle of code that you are putting a shell around. Apply returns your statement that executes the bundle of code that you gave it and surrounds it with a try/catch statement to catch the method failures.

The output for this method is:

I am beforeclassI am beforeI am a TestI am afterI am beforeI am a Failed TestI take a ScreenshotI am afterI am afterclass

Hope this helps!


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


What about using the ExternalResource rule ?
Looks like you it can give you enough flexibility to what you need.
And if this is not exactly what you need, take a look at the source code of external resource.
It's quite understandble how to implement a rule for example that will work only after the test invocation.