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?
hai qualche soluzione? –