2016-03-10 22 views
7

Sto cercando di capire come rieseguire i test falliti con l'uso di Espresso. Penso che sia un po 'più complicato dal comune caso di test di JUnit in quanto è necessario ripristinare lo stato nella tua app prima dell'avvio del test.Come rieseguire il test fallito in Espresso? - brainstorming

Il mio approccio è quello di creare il mio ActivityTestRule così ho appena copiato l'intero codice da questa classe e l'ho chiamato MyActivityTestRule.

In caso di test di strumentazione, la regola richiederà anche informazioni su come vogliamo iniziare la nostra attività. Preferisco lanciarlo da solo piuttosto che avere l'ambiente per farlo per me. Così, per esempio:

@Rule 
    public MyActivityTestRule<ActivityToStartWith> activityRule = new MyActivityTestRule<>(
      ActivityToStartWith.class, true, false 
    ); 

Così ho anche lanciare la mia attività nel metodo di annotazione @Before:

@Before 
    public void setUp() throws Exception { 
     activityRule.launchActivity(new Intent()); 
    } 

e fare pulizia nel metodo di annotazione @After:

@After 
    public void tearDown() throws Exception { 
     cleanUpDataBaseAfterTest(); 
     returnToStartingActivity(activityRule); 
    } 

Tali metodi - setUp(), tearDown() sono essenziali per essere chiamati prima/dopo ogni esecuzione di test - per garantire che lo stato dell'app durante l'avvio del test sia corretto.


All'interno MyActivityTestRule Ho apportato poche modifiche finora. La prima cosa è il cambiamento del metodo di applica a decorrere dal:

@Override 
    public Statement apply(final Statement base, Description description) { 
     return new ActivityStatement(super.apply(base, description)); 
    } 

E 'una cosa sconosciuta, ma per me, come ActivityStatement posto in ActivityTestRule ha metodo super.apply quindi avvolge anche la dichiarazione di prova in UiThreadStatement:

public class UiThreadStatement extends Statement { 
    private final Statement mBase; 
    private final boolean mRunOnUiThread; 

    public UiThreadStatement(Statement base, boolean runOnUiThread) { 
     mBase = base; 
     mRunOnUiThread = runOnUiThread; 
    } 

    @Override 
    public void evaluate() throws Throwable { 
     if (mRunOnUiThread) { 
      final AtomicReference<Throwable> exceptionRef = new AtomicReference<>(); 
      getInstrumentation().runOnMainSync(new Runnable() { 
       public void run() { 
        try { 
         mBase.evaluate(); 
        } catch (Throwable throwable) { 
         exceptionRef.set(throwable); 
        } 
       } 
      }); 
      Throwable throwable = exceptionRef.get(); 
      if (throwable != null) { 
       throw throwable; 
      } 
     } else { 
      mBase.evaluate(); 
     } 
    } 
} 

No, cosa faccio con i miei test, non posso mai creare case mRunOnUiThread boolean per essere vero. Sarà vero se nei miei casi di test saranno presenti test con annotazione @UiThreadTest - o questo è ciò che ho capito dal codice. Non accade mai, però, io non uso nulla del genere così ho deciso di ignorare questo UiThreadStatement e cambiare MyActivityTestRule a:

@Override 
    public Statement apply(final Statement base, Description description) { 
     return new ActivityStatement(base); 
    } 

E i miei casi di test gestita senza alcun problema. Grazie a che tutto quello che ho lasciato - che si avvolge attorno mBase.evaluate() è:

private class ActivityStatement extends Statement { 

    private final Statement mBase; 

    public ActivityStatement(Statement base) { 
     mBase = base; 
    } 

    @Override 
    public void evaluate() throws Throwable { 
     try { 
      if (mLaunchActivity) { 
       mActivity = launchActivity(getActivityIntent()); 
      } 
      mBase.evaluate(); 
     } finally { 
      finishActivity(); 
      afterActivityFinished(); 
     } 
    } 
} 

In launchActivity generale saranno chiamati solo se ho impostato nel 3 ° parametro del valore ActivityTestRule costruttore vero. Ma lancio test da solo in setUp() quindi non succede mai.

Da quello che ho capito mBase.evaluate() esegue il mio codice all'interno del metodo di annotazione @Test. Si ferma anche il caso di test durante il lancio del gettare. Questo significa che posso prenderlo e farlo ripartire - come se ci fosse proposto: How to Re-run failed JUnit tests immediately?

E va bene che ho fatto qualcosa di simile:

public class ActivityRetryStatement extends Statement { 

     private final Statement mBase; 
     private final int MAX_RUNS = 2; 

     public ActivityRetryStatement(Statement base) { 
      mBase = base; 
     } 

     @Override 
     public void evaluate() throws Throwable { 

      Throwable throwable = null; 

      for (int i = 0; i < MAX_RUNS; i++) { 

       try { 
        mBase.evaluate(); 
        // if you reach this lane that means evaluate passed 
        // and you don't need to do the next run 
        break; 
       } catch (Throwable t) { 

        // save first throwable if occurred 
        if (throwable == null) { 
         throwable = t; 
        } 

        // my try that didn't work 
        launchActivity(testInitialIntent); 
        // I've returned test to starting screen but 
        // mBase.envaluate() didn't make it run again 

        // it would be cool now to: 
        // - invoke @After 
        // - finish current activity 
        // - invoke @Before again and start activity 
        // - mBase.evaluate() should restart @Test on activity started again by @Before 
       } 
      } 

      finishActivity(); 
      afterActivityFinished(); 

      // if 1st try fail but 2nd passes inform me still that there was error 
      if (throwable != null) { 
       throw throwable; 
      } 
     } 
    } 

Quindi tali osservazioni in blocco catch sono i particolari non so come fare. Ho provato a eseguire launchActivity sull'intento che ho utilizzato in setUp() per eseguire il test per la prima volta. Ma mBase.evaluate() non ha fatto reagire (il test case non è andato di nuovo) - non è successo nulla + non mi avrebbe davvero salvato lì credo. Mi mancavano alcune iniziazioni che faccio in @SetUp, non è stato chiamato di nuovo.Mi piacerebbe davvero trovare un modo per riavviare correttamente l'intero ciclo di vita del test @Before @Test @After over again. Forse qualche chiamata su Instrumentation o TestRunner dal codice.

Qualche idea su come potrebbe essere fatto?

+0

hai qualche soluzione? –

risposta

0

La risposta è semplicissima. Assicurati di aggiornare i tuoi test per il caffè espresso a Junit 4, quindi vedi this answer

+0

Ho provato a mettere 'evaluate()' in loop ma cosa è successo -> il blocco del codice @Test è stato eseguito di nuovo, ma il dispositivo non ha reagito. Ha funzionato per te ON Espresso - non comuni test di Junit? (Sto usando Junit ver 4.12) – F1sher

+0

Sì, l'ho implementato nei nostri test Espresso e ha funzionato bene. È probabilmente il modo in cui stai configurando i tuoi test. Puoi pubblicare una sintesi di un test di esempio che include anche la regola Riprova come implementata nella risposta a cui mi sono collegato? – gorbysbm

+0

Ehi, grazie mille per questa informazione. Attualmente sono molto impegnato con il lavoro, ma di sicuro lo controllerò al più presto perché sono molto interessato a questo e ti darò un feedback se funzionasse o fornirò del codice in modo che possiamo controllare cosa sto facendo male :) – F1sher

Problemi correlati