web-dev-qa-db-fra.com

Le test de l'espresso échoue souvent avec une exception NoActivityResumedException

EDIT: Mise à jour de la description et du message d'erreur et ajout de quelques images. J'ai toujours ce problème. 

J'ai une erreur étrange qui se produit plusieurs fois lors de l'exécution de tests d'espresso. Après quelques tests réussis, les tests échouent avec l'exception suivante: 

   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)

J'ai une application simple avec une navigation vers les pages ne contenant que du texte à ce stade, et le test doit accéder à chaque page et identifier ce texte. 

@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");
}
}

Cette défaillance ne se produit que sur le périphérique réel. Sur les appareils émulés, les tests fonctionnent bien. Voir les images ci-dessous. 

Tous les tests sont exécutés par le script Gradle, en commençant par la suppression de l'application précédente et par la commande api, avant de la réinstaller. Assurer un environnement propre. Le journal indique que la désinstallation a réussi. Ensuite, déployez la nouvelle application et lancez l'exécution des tests. Maintenant, ils échouent. 

Si les tests ont échoué, ce n'est que lorsque je supprime manuellement l'application et l'interface de test de l'appareil que je peux obtenir à nouveau des tests réussis. Mais seulement pendant un certain temps jusqu'à ce que la même erreur se produise. 

Pourquoi ai-je une exception NoActivityResumedException? Je ne trouve pas un bon exemple de ce que c'est et de quand il se produit.

Device overview with only physical device failingFailing tests

31
peuhse

J'ai eu le même problème. Cela se produit lorsque l'écran de l'appareil est éteint. Allumer l'écran devrait résoudre le problème.

70
Artur Poznański

Vous pouvez réactiver votre appareil avant chaque test à l’aide de Uiautomator .

@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();
     }
}
8
Gordak

Pour éviter cela, laissez votre appareil rester éveillé. Il existe une option dans les options de développement du périphérique. 

Vous pouvez utiliser com.Android.ddmlib et une tâche Gradle pour modifier les paramètres du périphérique via adb pour chaque exécution et chaque périphérique sur lesquels vous testez.

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."
        }
    }
}

De plus, vous pouvez activer l'écran avec une autre tâche de gradé. (la condition préalable est qu'aucun paramétrage de PIN ou de déverrouillage ne soit défini) 

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
        }
    }
}

Laissez ces tâches s'exécuter avant votre tâche Gradle responsable des tests d'interface utilisateur.

Ainsi, aucun code supplémentaire dans vos tests n'est requis pour activer les périphériques et les maintenir en vie.

0
KraffMann