2015-08-21 12 views
9

Ho un'attività che utilizza una chiamata postDelayed:Espresso e postDelayed

public class SplashActivity extends Activity { 
    private Handler handler = new Handler(); 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(...); 
     handler.postDelayed(new Runnable() { 
      public void run() { finish(); } 
     }, 3000L); 
    } 
} 

Questo viene eseguito all'avvio dell'app, e ho bisogno di spostarsi e la mia schermata di login. Tuttavia, loopMainThreadUntilIdle di UIController non sembra prendere in considerazione il MessageQueue sottostante nel gestore. In quanto tale, questa azione termina immediatamente mentre sono ancora presenti messaggi nella coda.

onView(withId(R.id.splash_screen)).perform(new ViewAction() { 
    @Override 
    public Matcher<View> getConstraints() { 
     return isAssignableFrom(View.class); 
    } 

    @Override 
    public String getDescription() { 
     return ""; 
    } 

    @Override 
    public void perform(final UiController uiController, final View view) { 
     uiController.loopMainThreadUntilIdle(); 
    } 
}); 

Non riesco a capire come bloccare fino a quando la coda non viene scaricata. Android stesso mi sta impedendo di fare un sacco di cose che avrei provato (come estendere Handler e sovrascrivere il metodo postDelayed, ecc ...)

Qualcuno ha qualche suggerimento su come gestire postDelayed?

Preferirei evitare uiController.loopMainThreadForAtLeast, che sembra hacky (come un Thread.sleep sarebbe)

risposta

8

Quando Espresso aspetta, in realtà ci vuole in conto MessageQueue, ma in un modo diverso da quello che si pensa. Per essere inattivo, la coda deve essere vuota, oavere attività da eseguire in più di 15 millisecondi da ora.

È possibile controllare il codice da soli, in particolare il metodo loopUntil() in UiControllerImpl.java e il file QueueInterrogator.java. In quest'ultimo file troverai anche la logica di come Espresso controlla lo MessageQueue (metodo determineQueueState()).

Ora, come risolvere il tuo problema? Ci sono molti modi:

  1. Uso AsyncTask invece di Handler, dormire sul thread in background e l'esecuzione di azioni onPostExecute(). Questo fa sì che Espresso attenda il completamento di AsyncTask, ma potrebbe non piacerti il ​​sovraccarico di un altro thread.

  2. Dormire nel codice di test, ma non ti piace già questo approccio.

  3. Scrivi la tua ordinazione IdlingResource: questo è un meccanismo generale per far sapere a Espresso quando qualcosa è inattivo, in modo che possa eseguire azioni e asserzioni.Per questo approccio si potrebbe:

    • utilizzare la classe CountingIdlingResource che viene fornito con Espresso

    • chiamata increment() quando inviate il vostro eseguibile e decrement() all'interno del eseguibile dopo la logica ha eseguito

    • Pubblica il tuo negozio IdlingResource nella configurazione di prova e annullarlo nella rimozione

Consulta anche: docs and sample, another sample

+1

Sto pensando che potrei semplicemente astrarre la spinta del messaggio sulla coda e iniettare qualche altra implementazione che funge da IdlingResource. Avrò un'implementazione predefinita nel mio codice che rimanda al gestore e nel codice di test uno che è un IdlingResource e icnrements/decrements – Matt

0

Per quanto ne so non c'è nessuna attesa per l'attività per terminare metodo espresso. È possibile implementare la propria versione di waitForCondition, qualcosa che robotium ha. In questo modo, attendi solo per il tempo necessario e puoi rilevare i problemi relativi alla mancata attività dell'attività.

Fonderesti praticamente tutte le tue condizioni ogni x ms, qualcosa del genere.

while (!conditionIsMet() && currentTime < timeOut){ 
    sleep(100); 
} 

boolean conditionIsMet() { 
    return "espresso check for if your splash view exists"; 
} 
+0

Il problema è che Android si fornisce alcun modo per guardare davvero in coda dei messaggi per vedere se qualcosa è in coda. Dovrebbe essere qualcosa che è stato intercettato e sostituito al momento dell'avvio (che penso sia ciò che fa robotium). – Matt

+0

La classe waitForCondition esegue solo il polling come condizione per scrivere se stessi. Per quanto riguarda il robotium che controlla la coda, non credo, ho visto problemi come quello che stai avendo con robotium. – JohanShogun

+0

Per questo caso d'uso dovresti essere in grado di aspettare che l'azione abbia avuto luogo, invece di guardare la coda dei messaggi (che è davvero più interessante da un punto di prova). – JohanShogun