Ich versuche herauszufinden, wie fehlgeschlagene Tests mit der Verwendung von Espresso erneut ausgeführt werden. Ich denke, es ist ein wenig komplizierter als bei herkömmlichen JUnit-Testfällen, da Sie den Status in Ihrer App vor dem Teststart wiederherstellen müssen.Wie wiederholen Test in Espresso fehlgeschlagen? - Brainstorming
Meine Herangehensweise besteht darin, meine eigene ActivityTestRule zu erstellen, also kopiere ich ganzen Code aus dieser Klasse und nannte sie MyActivityTestRule.
Im Falle von Instrumentierungstests benötigt die Regel auch Informationen darüber, wie wir unsere Aktivität starten möchten. Ich ziehe es vor, es selbst zu starten, anstatt eine Umgebung für mich zu haben. So zum Beispiel:
@Rule
public MyActivityTestRule<ActivityToStartWith> activityRule = new MyActivityTestRule<>(
ActivityToStartWith.class, true, false
);
So starte ich auch meine Tätigkeit in @Before Anmerkung Methode:
@Before
public void setUp() throws Exception {
activityRule.launchActivity(new Intent());
}
Und in @After Anmerkung Methode machen aufzuräumen:
@After
public void tearDown() throws Exception {
cleanUpDataBaseAfterTest();
returnToStartingActivity(activityRule);
}
Diese Methoden - setUp(), tearDown() müssen unbedingt vor/nach jedem Testlauf aufgerufen werden, um sicherzustellen, dass der App-Zustand während des Testbeginns korrekt ist.
Inside MyActivityTestRule Ich habe bisher nur wenige Änderungen vorgenommen. Das erste, was ist Wechsel gelten Methode aus:
@Override
public Statement apply(final Statement base, Description description) {
return new ActivityStatement(super.apply(base, description));
}
Es ist eine unbekannte, aber ist für mich, wie ActivityStatement in ActivityTestRule platziert super.apply Methode hat, damit es auch Test-Anweisung in UiThreadStatement wickelt:
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();
}
}
}
Nein, was ich mit meinen Tests mache, ich kann niemals Case mRunOnUiThread boolean erstellen, um wahr zu sein. Es wird wahr sein, wenn in meinen Testfällen Tests mit Annotation @UiThreadTest vorhanden sein werden - oder das habe ich aus Code verstanden. Es passiert nie, obwohl ich nicht verwenden so etwas so habe ich beschlossen, diese UiThreadStatement zu ignorieren und ändern MyActivityTestRule zu:
@Override
public Statement apply(final Statement base, Description description) {
return new ActivityStatement(base);
}
Und meine Testfälle ohne Probleme laufen. Dank dieser alles, was ich verlassen haben -, die um mBase.evaluate Wraps() ist:
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();
}
}
}
Im Allgemeinen launchActivity wird nur aufgerufen werden, wenn ich wahr im 3. Parameter von ActivityTestRule Konstruktor Wert gesetzt. Aber ich starte Tests selbst in setUp(), so dass es nie passiert.
Von was ich verstanden mBase.evaluate() führt meinen Code innerhalb @Test Annotationsmethode. Es stoppt auch den Testfall während des Werfenwurfs. Das bedeutet, dass ich es fangen kann, und starten Sie es - wie vorgeschlagen: How to Re-run failed JUnit tests immediately?
Und okay, ich habe so etwas wie das:
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;
}
}
}
Also diese Kommentare in catch-Block sind Teile Ich weiß nicht, wie man machen. Ich habe versucht, launchActivity auf Absicht, die ich in setUp() verwendet, um den Test zum ersten Mal auszuführen. Aber mBase.evaluate() ließ es nicht reagieren (Testfall ging nicht wieder) - nichts passierte + es würde mich dort nicht wirklich retten, denke ich. Mir fehlten einige Initiationen, die ich in @SetUp mache, es wurde nicht erneut aufgerufen.Ich würde wirklich gerne einen Weg finden, wie man den gesamten Testlebenszyklus @Before @Test @ After wieder richtig startet. Vielleicht rufen einige Instrumentation oder TestRunner aus dem Code.
Irgendwelche Gedanken darüber, wie es gemacht werden könnte?
haben Sie irgendwelche Lösungen? –