BEARBEITEN: Beschreibung und Fehlermeldung aktualisiert und einige Bilder hinzugefügt. Habe immer noch dieses Problem.
Ich habe einen seltsamen Fehler, der oft beim Ausführen von Espresso-Tests auftritt. Nach einigen erfolgreichen Testläufen schlagen die Tests mit folgender Ausnahme fehl:
06-23 13:04:48.438 info TestRunner failed: WhenNavigatingToReportsThenCorrectViewShouldBeShown(com.myapp.ui.views.MainActivityTest)
06-23 13:04:48.439 info TestRunner ----- begin exception -----
06-23 13:04:48.441 info TestRunner Android.support.test.espresso.NoActivityResumedException: No activities in stage RESUMED. Did you forget to launch the activity. (test.getActivity() or similar)?
06-23 13:04:48.441 info TestRunner at dalvik.system.VMStack.getThreadStackTrace(Native Method)
06-23 13:04:48.441 info TestRunner at Java.lang.Thread.getStackTrace(Thread.Java:580)
06-23 13:04:48.441 info TestRunner at Android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.Java:82)
06-23 13:04:48.441 info TestRunner at Android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.Java:53)
06-23 13:04:48.441 info TestRunner at Android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.Java:184)
06-23 13:04:48.441 info TestRunner at Android.support.test.espresso.ViewInteraction.doPerform(ViewInteraction.Java:115)
06-23 13:04:48.441 info TestRunner at Android.support.test.espresso.ViewInteraction.perform(ViewInteraction.Java:87)
06-23 13:04:48.441 info TestRunner at com.myapp.ui.views.MainActivityTest.WhenNavigatingToReportsThenCorrectViewShouldBeShown(MainActivityTest.Java:96)
06-23 13:04:48.441 info TestRunner at Java.lang.reflect.Method.invoke(Native Method)
06-23 13:04:48.441 info TestRunner at Java.lang.reflect.Method.invoke(Method.Java:372)
06-23 13:04:48.441 info TestRunner at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.Java:45)
06-23 13:04:48.441 info TestRunner at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.Java:15)
06-23 13:04:48.441 info TestRunner at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.Java:42)
06-23 13:04:48.441 info TestRunner at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.Java:20)
06-23 13:04:48.441 info TestRunner at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.Java:28)
06-23 13:04:48.441 info TestRunner at Android.support.test.internal.statement.UiThreadStatement.evaluate(UiThreadStatement.Java:55)
06-23 13:04:48.441 info TestRunner at Android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.Java:257)
06-23 13:04:48.441 info TestRunner at org.junit.rules.RunRules.evaluate(RunRules.Java:18)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner.runLeaf(ParentRunner.Java:263)
06-23 13:04:48.441 info TestRunner at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.Java:68)
06-23 13:04:48.441 info TestRunner at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.Java:47)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner$3.run(ParentRunner.Java:231)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner$1.schedule(ParentRunner.Java:60)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner.runChildren(ParentRunner.Java:229)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner.access$000(ParentRunner.Java:50)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.Java:222)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner.run(ParentRunner.Java:300)
06-23 13:04:48.441 info TestRunner at org.junit.runners.Suite.runChild(Suite.Java:128)
06-23 13:04:48.441 info TestRunner at org.junit.runners.Suite.runChild(Suite.Java:24)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner$3.run(ParentRunner.Java:231)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner$1.schedule(ParentRunner.Java:60)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner.runChildren(ParentRunner.Java:229)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner.access$000(ParentRunner.Java:50)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.Java:222)
06-23 13:04:48.441 info TestRunner at org.junit.runners.ParentRunner.run(ParentRunner.Java:300)
06-23 13:04:48.441 info TestRunner at org.junit.runner.JUnitCore.run(JUnitCore.Java:157)
06-23 13:04:48.441 info TestRunner at org.junit.runner.JUnitCore.run(JUnitCore.Java:136)
06-23 13:04:48.441 info TestRunner at Android.support.test.internal.runner.TestExecutor.execute(TestExecutor.Java:54)
06-23 13:04:48.441 info TestRunner at Android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.Java:228)
06-23 13:04:48.441 info TestRunner at Android.app.Instrumentation$InstrumentationThread.run(Instrumentation.Java:1837)
06-23 13:04:48.441 info TestRunner ----- end exception -----
06-23 13:04:48.443 info TestRunner finished: WhenNavigatingToReportsThenCorrectViewShouldBeShown(com.myapp.ui.views.MainActivityTest)
Ich habe eine einfache App mit Navigation zu Seiten, die an dieser Stelle nur Text enthalten, und der Test sollte zu jeder Seite navigieren und diesen Text identifizieren.
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MainActivityTest {
@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule(MainActivity.class);
private MainActivity mainActivity;
@Before
public void setActivity() {
mainActivity = mActivityRule.getActivity();
}
@Test
public void WhenNavigatingToReportsThenCorrectViewShouldBeShown() {
onView(allOf(withId(R.id.icon), hasSibling(withText(R.string.reports)))).perform(click());
onView(withText("This is the Reports Activity.")).check(matches(isDisplayed()));
Spoon.screenshot(mainActivity, "main_view");
}
}
Dieser Fehler tritt nur auf dem realen Gerät auf. Bei einem emulierten Gerät funktionieren die Tests einwandfrei. Siehe Bilder unten.
Alle Tests werden mit einem Gradle-Skript ausgeführt. Beginnen Sie mit dem Entfernen der vorherigen App und der Test-API, bevor Sie sie erneut installieren. Um eine saubere Umwelt zu gewährleisten. Das Protokoll zeigt an, dass die Deinstallation erfolgreich war. Dann stellen Sie die neue App bereit und starten Sie die Tests. Jetzt scheitern sie.
Wenn die Tests fehlgeschlagen sind, kann ich die App und die Test-API vom Gerät manuell entfernen, um wieder erfolgreiche Tests zu erhalten. Aber nur für eine Weile, bis der gleiche Fehler auftritt.
Warum bekomme ich NoActivityResumedException? Ich kann kein gutes Beispiel dafür finden, was es ist und wann es auftritt.
Ich hatte das gleiche Problem. Dies geschieht, wenn der Bildschirm auf dem Gerät ausgeschaltet ist. Schalten Sie den Bildschirm ein, um das Problem zu beheben.
Sie können Ihr Gerät vor jedem Test mit Uiautomator aufwecken.
@Before
public void init(){
UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
Point[] coordinates = new Point[4];
coordinates[0] = new Point(248, 1520);
coordinates[1] = new Point(248, 929);
coordinates[2] = new Point(796, 1520);
coordinates[3] = new Point(796, 929);
try {
if (!uiDevice.isScreenOn()) {
uiDevice.wakeUp();
uiDevice.swipe(coordinates, 10);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
Hauptsächlich liegt der Fehler darin, dass Ihre Verbindung, wenn sie sich nicht in einem aktiven Modus befindet, nicht im Ruhezustand sein sollte, und dass sie sich auch in der App befinden muss, in der die Testfälle geschrieben wurden. Angenommen, Sie haben bereits die Startregel @Rule Activity verwendet.
Eine mögliche Ursache hierfür sind die parallel laufenden Tests. Verwenden --no-parallel
.
Beispiel -> gradlew connectedLiveDebugAndroidTest --no-parallel
Dies geschieht nur, wenn alle von der Konsole oder nacheinander ausgeführt werden, aber nicht einzeln, sondern wahrscheinlich parallel auf demselben Gerät. Zwei verschiedene Espresso-Tests, die gleichzeitig auf demselben Gerät ausgeführt werden, führen dazu, dass sie schuppig werden und fehleranfällig sind.
Lassen Sie Ihr Gerät wach bleiben, um dies zu vermeiden. Es gibt eine Option in den Entwickleroptionen des Geräts.
Sie können com.Android.ddmlib und eine Gradle-Task verwenden, um die Geräteeinstellungen über adb für jeden Build-Lauf und jedes Gerät, auf dem Sie testen, zu ändern.
import com.Android.ddmlib.AndroidDebugBridge
import com.Android.ddmlib.CollectingOutputReceiver
import com.Android.ddmlib.IDevice
import com.Android.ddmlib.NullOutputReceiver
task stayAwake {
description = "Activate the Stay Awake settings in the developer options."
group = "Device Setup"
AndroidDebugBridge.initIfNeeded(false)
def bridge = AndroidDebugBridge.createBridge(Android.adbExecutable.path, false)
doLast {
bridge.devices.each {
it.executeShellCommand("settings put global stay_on_while_plugged_in 3", NullOutputReceiver.receiver)
println "Device ${it} will stay awake."
}
}
}
Zusätzlich können Sie den Bildschirm mit einer anderen Gradelaufgabe aktivieren. (Voraussetzung ist, dass kein PIN oder Entsperrmuster eingestellt ist)
IDevice.metaClass.inputKeyEventByShell {
delegate.executeShellCommand("input keyevent ${it}", NullOutputReceiver.receiver)
}
IDevice.metaClass.inputSwipeByShell {
delegate.executeShellCommand("input swipe ${it}", NullOutputReceiver.receiver)
}
task unlockScreen {
description = "Activate screen and unlock device."
group = "Device Setup"
AndroidDebugBridge.initIfNeeded(false)
def bridge = AndroidDebugBridge.createBridge(Android.adbExecutable.path, false)
doLast {
bridge.devices.each {
def receiver = CollectingOutputReceiver.newInstance()
it.executeShellCommand("dumpsys power | grep \"mHolding\"", receiver)
def displaySuspendFalse = receiver.getOutput().find("mHoldingDisplaySuspendBlocker=false")
def wakelockSuspendFalse = receiver.getOutput().find("mHoldingWakeLockSuspendBlocker")
if (displaySuspendFalse || wakelockSuspendFalse) {
it.inputKeyEventByShell('26') //power keyevent
println "Screen of device $it activated & unlocked."
}
it.inputSwipeByShell('100 500 100 1450 100') //swipe action
}
}
}
Lassen Sie diese Aufgaben vor der für die UI-Tests zuständigen Gradel-Aufgabe laufen.
Auf diese Weise ist in Ihren Tests kein zusätzlicher Code erforderlich, um die Geräte zu aktivieren und am Leben zu erhalten.