2015-04-09 4 views
10

Ich habe eine Ansicht, in der ein Element mit dem folgend in einer Endlos-Schleife animiert:Espresso auf Sicht Einfrieren mit Looping Animation

<translate 
    android:fromXDelta="0%" 
    android:toXDelta="100%" 
    android:duration="10000" 
    android:repeatCount="-1" 
    android:repeatMode="reverse"/> 

Wenn Espresso meine Tätigkeit öffnet, es ist in der Lage, einige Operationen durchzuführen, aber schnell gefriert . Ich nehme an, Espresso wartet darauf, dass der UI-Thread inaktiv wird, was in diesem Fall nie passiert.

Kann ich diese Ansicht nur testen, um einen Mechanismus zum Deaktivieren von Animationen zu implementieren? Ich könnte eine andere Klasse mit Animationen behandeln, die für Tests verspottet werden. Oder bauen Sie Zeitbedingungen auf.

Edit: Ich habe noch ein Beispielprojekt zu erstellen, um zu versuchen, das Problem neu zu erstellen, aber hier sind einige weitere Details in der Zwischenzeit:

1) I Jake Wharton ActivityRule meiner Tätigkeit bin mit haben, automatisch gestartet (https://gist.github.com/JakeWharton/1c2f2cadab2ddd97f9fb).

2) Dies ist mein Test:

onView(withId(R.id.btn_yes)).perform(click()); 

3) der komplette Stack-Trace ist. Beachten Sie die AppNotIdleException:

Running tests 
Test running started 
android.support.test.espresso.PerformException: Error performing 'single click' on view 'with id: com.myapp:id/btn_yes'. 
at android.support.test.espresso.PerformException$Builder.build(PerformException.java:83) 
at android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:70) 
at android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:53) 
at android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:185) 
at android.support.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:115) 
at android.support.test.espresso.ViewInteraction.perform(ViewInteraction.java:87) 
at com.myapp.espresso.MyActivityTest.yesButtonTest(MyActivityTest.java:53) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) 
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) 
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) 
at com.myapp.espresso.ActivityRule$2.evaluate(ActivityRule.java:129) 
at org.junit.rules.RunRules.evaluate(RunRules.java:18) 
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) 
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) 
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) 
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) 
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) 
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) 
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) 
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) 
at org.junit.runners.ParentRunner.run(ParentRunner.java:300) 
at org.junit.runners.Suite.runChild(Suite.java:128) 
at org.junit.runners.Suite.runChild(Suite.java:24) 
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) 
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) 
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) 
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) 
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) 
at org.junit.runners.ParentRunner.run(ParentRunner.java:300) 
at org.junit.runner.JUnitCore.run(JUnitCore.java:157) 
at org.junit.runner.JUnitCore.run(JUnitCore.java:136) 
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:270) 
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1837) 
Caused by: android.support.test.espresso.AppNotIdleException: Looped for 3580 iterations over 60 SECONDS. The following Idle Conditions failed . 
at android.support.test.espresso.IdlingPolicy.handleTimeout(IdlingPolicy.java:61) 
at android.support.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:471) 
at android.support.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:402) 
at android.support.test.espresso.base.UiControllerImpl.injectMotionEvent(UiControllerImpl.java:226) 
at android.support.test.espresso.action.MotionEvents.sendDown(MotionEvents.java:78) 
at android.support.test.espresso.action.Tap.sendSingleTap(Tap.java:133) 
at android.support.test.espresso.action.Tap.access$100(Tap.java:35) 
at android.support.test.espresso.action.Tap$1.sendTap(Tap.java:40) 
at android.support.test.espresso.action.GeneralClickAction.perform(GeneralClickAction.java:98) 
at android.support.test.espresso.ViewInteraction$1.run(ViewInteraction.java:144) 
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) 
at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
at android.os.Handler.handleCallback(Handler.java:739) 
at android.os.Handler.dispatchMessage(Handler.java:95) 
at android.os.Looper.loop(Looper.java:135) 
at android.app.ActivityThread.main(ActivityThread.java:5221) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694) 

4) Stack-Traces, wenn die Ausführung des Tests pausieren, während es gefroren ist:

Thema # 1:

"Instr: [email protected]" prio=5 waiting 
    java.lang.Thread.State: WAITING 
    blocks Instr: [email protected] 
     at java.lang.Object.wait(Object.java:-1) 
     at java.lang.Thread.parkFor(Thread.java:1220) 
     - locked <0x13a3> (a java.lang.Object) 
     at sun.misc.Unsafe.park(Unsafe.java:299) 
     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:157) 
     at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:400) 
     at java.util.concurrent.FutureTask.get(FutureTask.java:162) 
     at android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:181) 
     at android.support.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:115) 
     at android.support.test.espresso.ViewInteraction.perform(ViewInteraction.java:87) 

Thread # 2:

"[email protected]" prio=5 runnable 
    java.lang.Thread.State: RUNNABLE 
     at android.view.ThreadedRenderer.nSyncAndDrawFrame(ThreadedRenderer.java:-1) 
     at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:333) 
     at android.view.ViewRootImpl.draw(ViewRootImpl.java:2492) 
     at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2337) 
     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1968) 
     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1054) 
     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5779) 
     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767) 
     at android.view.Choreographer.doCallbacks(Choreographer.java:580) 
     at android.view.Choreographer.doFrame(Choreographer.java:550) 
     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753) 
     at android.os.Handler.handleCallback(Handler.java:739) 
     at android.os.Handler.dispatchMessage(Handler.java:95) 
     at android.support.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:461) 
     at android.support.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:402) 
     at android.support.test.espresso.base.UiControllerImpl.injectMotionEvent(UiControllerImpl.java:226) 
     at android.support.test.espresso.action.MotionEvents.sendDown(MotionEvents.java:78) 
     at android.support.test.espresso.action.Tap.sendSingleTap(Tap.java:133) 
     at android.support.test.espresso.action.Tap.access$100(Tap.java:35) 
     at android.support.test.espresso.action.Tap$1.sendTap(Tap.java:40) 
     at android.support.test.espresso.action.GeneralClickAction.perform(GeneralClickAction.java:98) 
     at android.support.test.espresso.ViewInteraction$1.run(ViewInteraction.java:144) 
     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) 
     at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
     at android.os.Handler.handleCallback(Handler.java:739) 
     at android.os.Handler.dispatchMessage(Handler.java:95) 
     at android.os.Looper.loop(Looper.java:135) 
     at android.app.ActivityThread.main(ActivityThread.java:5221) 
     at java.lang.reflect.Method.invoke(Method.java:-1) 
     at java.lang.reflect.Method.invoke(Method.java:372) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694) 
+0

Mein Verständnis ist, dass 'MessageQueue' sich selbst als inaktiv ansieht, wenn keine Nachrichten * gerade jetzt * bereit sind, also sollte eine unendliche Animation das nicht verhindern. Ich würde deine App mit dem 'Monitor'-Tool profilieren, um zu sehen, was sonst noch im Hauptthread passiert. Vielleicht programmiert sich ein schlechter Code wiederholt selbst ohne Verzögerung. –

+0

Der UI-Thread wird als inaktiv betrachtet, wenn die Nachrichtenwarteschlange leer ist oder wenn getWhen() - now() weniger als 17 ms beträgt. Eine Animation blockiert also ui thread. Dennoch entspricht das, was Sie beschreiben, nicht den üblichen Symptomen. Wenn der UI-Thread 60 Sekunden lang nicht inaktiv ist, wird Espresso den Test mit einer entsprechenden Ausnahme abbrechen. @mieroy: Hast du so lange gewartet? Wenn Sie den Test im Debug-Modus ausführen und die Ausführung im Debugger unterbrechen, wie lautet die Stack-Ablaufverfolgung, die Sie für den Testausführungsthread erhalten haben, und was für den Hauptthread Ihrer App? – haffax

+0

@haffax, habe ich zu meiner Frage 3 Stack Traces hinzugefügt: Test Runner & Main Threads während der Ausführung (Punkt # 4) und des Fehlers nach 60s (Punkt # 3). Ich muss zugeben, dass ich nicht gut verstehe, wie Animationsereignisse geplant sind und wie der Leerlauferkennungsmechanismus funktioniert. – siger

Antwort

12

Ja, das Problem, das Sie mit dem Test haben, ist auf die Animation zurückzuführen.

Die einzige Lösung, die ich mir vorstellen kann, ist in der Tat die unendlichen Animationen zu deaktivieren.

Im Allgemeinen ist es eine gute Idee, Animationen zu deaktivieren, wenn Funktionstests ausgeführt werden, da sie immer eine gewisse Schärfe verursachen.

Ein wenig Hintergrund:

Der Faden UI ist niemals im Leerlauf von Espresso Sicht, weil die Nachrichtenwarteschlange immer ein Ereignis enthält, die für die Handhabung näher als die Schwellen geplant wird verwendet, um zu bestimmen, ob Thread inaktiv ist.

Wenn Sie QueueInterrogator betrachten, können Sie sehen, dass determineQueueState()TASK_DUE_SOON zurückgibt, wenn die Nachrichtenwarteschlange ein Ereignis enthält, das in weniger als 16 ms verarbeitet werden soll. UiController führt die Ausführung nur fort, wenn alle Leerlaufbedingungen erfüllt sind. Im Fall von QueueInterrogator ist dies nur der Fall, wenn die Nachrichtenwarteschlange leer ist oder die nächste Nachricht für die Verarbeitung in 16ms oder später geplant ist.

Animationen werden die View ungültig machen sie transformieren, und dies wird eine neue Ansichtshierarchie Traversal durch die Choreographer auslösen. Und diese Auslösenachricht, die von ViewRoot zu Choreographer kommt, ist das, was Ihre Nachrichtenwarteschlange der UI-Thread nicht im Leerlauf hält.

+0

Danke für die detaillierte Untersuchung. Ich kam zu dem Schluss, dass dies wahr ist;) Interessanterweise wurde das Problem durch das Ändern meiner Animationen von der Verwendung des Animations "Frameworks" zum Animator gelöst. Jetzt habe ich das umgekehrte Problem, dass ich Espresso nicht dazu bringen kann, auf andere (endliche) Animationen zu warten, bevor ich mit Auswertungen fortfahre :) Ich muss immer noch eine Möglichkeit implementieren, Animationen für (Espresso) -Tests zu deaktivieren. Vielen Dank! – siger