web-dev-qa-db-ja.com

エスプレッソテストがNoActivityResumedExceptionで頻繁に失敗する

編集:説明とエラーメッセージを更新し、いくつかの画像を追加しました。まだこの問題があります。

エスプレッソテストの実行中に何度も発生する奇妙なエラーがあります。いくつかのテストが正常に実行された後、次の例外でテストが失敗し始めます。

   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)

この時点でテキストのみを含むページへのナビゲーションを備えたシンプルなアプリがあり、テストでは各ページにナビゲートしてこのテキストを特定する必要があります。

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

この障害は、実際のデバイスでのみ発生します。エミュレートされたデバイスでは、テストは正常に機能します。以下の画像をご覧ください。

すべてのテストは、以前のアプリとテストAPIを削除してから再度インストールするまで、gradleスクリプトによって実行されます。クリーンな環境を確保するため。ログは、アンインストールが成功したことを示しています。次に、新しいアプリをデプロイして、テストの実行を開始します。今、彼らは失敗します。

テストが失敗した場合、デバイスからアプリとテストAPIを手動で削除するまで、テストが成功することはありません。ただし、同じエラーが発生するまでしばらくの間だけです。

なぜNoActivityResumedExceptionが発生するのか、それが何であるか、いつ発生するかの良い例が見つかりません。

Device overview with only physical device failingFailing tests

37
peuhse

同じ問題がありました。これは、デバイスの画面がオフのときに発生します。画面をオンにすると問題が解決するはずです。

79

iautomator を使用して、すべてのテストの前にデバイスを起動できます。

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

主なエラーは、接続がアクティブモードでない場合、テストケースが記述されたアプリ内にある必要があるため、スリープモードになってはならないためです。すでに@Ruleアクティビティ起動ルールを使用していると仮定します。

2
user11479360

この原因の1つは、テストが並行して実行されていることです。使用する --no-parallel

例-> gradlew connectedLiveDebugAndroidTest --no-parallel

これは、すべてをコンソールからまたは連続して実行する場合にのみ発生しますが、個別に実行する場合は発生せず、同じデバイスで並行して実行される可能性があります。同じデバイスで同時に2つの異なるEspressoテストを実行すると、不安定で失敗しやすくなります。

0
Sotti

これを回避するには、デバイスをスリープ状態にしないでください。デバイスの開発者向けオプションにはオプションがあります。

Com.Android.ddmlibとgradleタスクを使用して、ビルド実行ごとおよびテスト対象のすべてのデバイスのadb経由でデバイス設定を変更できます。

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

さらに、別のgradleタスクで画面をアクティブ化できます。 (前提条件は、PINまたはロック解除パターンが設定されていないことです)

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

これらのタスクは、UIテストを担当するgradleタスクの前に実行してください。

このように、デバイスをアクティブにしてそれらを維持するために、テストで追加のコードは必要ありません。

0
KraffMann