Applicare ‘@Regola’ dopo ogni ‘@Test’ e prima di ogni ‘@Dopo’ in JUnit

Ho una suite di test in cui sono disconnettersi dal sistema in @After e la chiusura del browser in @AfterClass. Sto cercando di utilizzare @Rule di prendere un test non riuscito screenshot con Selenio per ogni metodo di test. Ho controllato manualmente che @Rule solo viene eseguito prima di ogni @Before ma voglio impostare dopo @Test e prima di @After. Non riuscivo a trovare soluzione semplice. Qualsiasi aiuto sarà apprezzato.

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

L’uscita di sto ottenendo è

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
  • Già detto, ho solo voglia di fare screen shot solo quando si verifica un esito negativo. Non per tutti i test 😀
  • Divertente. Ero solo interessato in ordine, quindi in realtà la tua domanda è stata la mia risposta 🙂
  • Io sono contento!
  • in realtà l’indicato ordine non è corretto, come si mostra solo quando la regola viene creata un’istanza, non quando è applicato. Il test corretto non sarebbe un constuctor in Regola a tutti, ma la chiamata arg0.evaluate() di registrazione prima e dopo la chiamata. Questo vuole dimostrare che la regola viene eseguita intorno @Before / @After come è notato anche in JavaDoc di JUnit.

 

3 Replies
  1. 22

    Causa del modo in cui sono impostate regole, non si può avere una regola che viene dopo la @prima o prima di @dopo. Si può pensare di regole come le conchiglie che hai messo sul metodo di prova. Il primo guscio a @prima/@dopo. Dopo la @le regole vengono applicate.

    Un modo rapido per fare quello che vuoi fare è quello di evitare @Dopo tutto. Una regola può essere creato in modo che prendere uno screenshot se un metodo ha esito negativo e quindi eseguire il vostro dopo il codice. Non è molto bella come @Dopo, ma funziona. (inoltre ho implementato TestRule perché MethodRule è stato ammortizzato).

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

    Tutto il lavoro della regola è fatto in una dichiarazione. Un org.junit.i corridori.modello.La dichiarazione è una classe che rappresenta un fascio di codice. Allora, ecco il applicare metodo riceve il fascio di codice che si sta mettendo un guscio intorno. Applicare restituisce la sua dichiarazione che esegue il bundle di codice che hai dato e la circonda con un’istruzione try/catch per catturare gli errori di metodo.

    L’uscita di questo metodo è:

    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

    Spero che questo aiuta!

    • Troy, Grazie per il tuo commento. Ha suggerimenti la vostra soluzione.
    • Vorrei suggerire di aggiungere @After con il metodo di uscita, pertanto sarà visibile, che baseStatement.valutare() provoca in realtà @Before, quindi il metodo di prova, poi @After per l’esecuzione.
  2. 4
    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. 1

    Che cosa circa usando il ExternalResource regola ?

    Sembra che si può dare la flessibilità sufficiente per quello che ti serve.

    E se questo non è esattamente ciò di cui avete bisogno, date un’occhiata al il codice sorgente di una risorsa esterna.
    È abbastanza understandble come implementare una regola, per esempio, che solo dopo il test di chiamata.

Lascia un commento