Back

Explore Courses Blog Tutorials Interview Questions
0 votes
2 views
in DevOps and Agile by (19.7k points)

I have a test suite where I am logging out of the system in @After and closing the browser in @AfterClass. I am trying to use @Rule to take a failed test screenshot using Selenium for every test method. I checked manually that @Rule only runs before every @Before but I want to set it up after @Test and before @After. I couldn't find out a simple solution. Any help will be appreciated.

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;

    }    

}     

The output I am getting is

I am beforeclass

I am rule

I am befor

I am Test

I am after

I am rule

I am before

I am Test2

I am after

I am afterclass     

1 Answer

0 votes
by (62.9k points)

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. The 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 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

Browse Categories

...