我正在使用Robolectric在本地JVM上进行单元测试。
当我单击按钮时,我得到androidx.test.espresso.PerformException:执行“单击-坐标时出错”。
@Test
public void givenVerificationCodeEmpty_whenUserPressVerify_thenErrorMustAppear() {
ActivityScenario.launch(VerifyAccountActivity.class);
onView(withId(R.id.verify_account_verify_button)).perform(click());
String error = context.getString(R.string.error_verification_code_empty);
onView(withId(R.id.verify_code_input)).check(matches(hasErrorText(error)));
}
我正在使用Android Studio 3.3.2和Robolectric 4.2。
绑定到按钮的动作涉及到view.requestFocus(),如代码所示
private void verify() {
mVerificationCodeView.setError(null);
String code = mVerificationCodeView.getText().toString();
if(TextUtils.isEmpty(code)) {
mVerificationCodeView.setError(getResources().getString(R.string.error_verification_code_empty));
mVerificationCodeView.requestFocus();
} else {
showProgress(true);
}
}
这是完整的错误堆栈
androidx.test.espresso.PerformException: Error performing 'single click - At Coordinates: 159, 372 and precision: 16, 16' on view 'with id: com.syriail.aladdin:id/verify_account_verify_button'.
at androidx.test.espresso.PerformException$Builder.build(PerformException.java:82)
at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:79)
at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:51)
at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:312)
at androidx.test.espresso.ViewInteraction.desugaredPerform(ViewInteraction.java:173)
at androidx.test.espresso.ViewInteraction.perform(ViewInteraction.java:114)
at com.syriail.aladdin.useraccount.VerifyAccountUnitTest.givenVerificationCodeEmpty_whenUserPressVerify_thenErrorMustAppear(VerifyAccountUnitTest.java:83)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:256)
at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at android.widget.PopupWindow.getDecorViewLayoutParams(PopupWindow.java:2201)
at android.widget.PopupWindow.update(PopupWindow.java:2257)
at android.widget.PopupWindow.update(PopupWindow.java:2235)
at android.widget.Editor.setFrame(Editor.java:868)
at android.widget.TextView.setFrame(TextView.java:6481)
at android.view.View.layout(View.java:20669)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at com.google.android.material.textfield.TextInputLayout.onLayout(TextInputLayout.java:1885)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at androidx.appcompat.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:444)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:753)
at android.view.View.layout(View.java:20672)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2792)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2319)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1460)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7183)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at org.robolectric.shadows.ShadowMessageQueue.dispatchMessage(ShadowMessageQueue.java:148)
at org.robolectric.shadows.ShadowMessageQueue.access$200(ShadowMessageQueue.java:38)
at org.robolectric.shadows.ShadowMessageQueue$1.run(ShadowMessageQueue.java:126)
at org.robolectric.util.Scheduler$ScheduledRunnable.run(Scheduler.java:386)
at org.robolectric.util.Scheduler.runOneTask(Scheduler.java:278)
at org.robolectric.util.Scheduler.advanceTo(Scheduler.java:260)
at org.robolectric.util.Scheduler.advanceBy(Scheduler.java:243)
at org.robolectric.util.Scheduler.advanceBy(Scheduler.java:233)
at org.robolectric.util.Scheduler.setIdleState(Scheduler.java:88)
at org.robolectric.util.Scheduler.unPause(Scheduler.java:123)
at org.robolectric.shadows.ShadowLooper.unPause(ShadowLooper.java:347)
at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:398)
at org.robolectric.shadows.ShadowViewGroup.addView(ShadowViewGroup.java:27)
at android.view.ViewGroup.addView(ViewGroup.java)
at android.view.ViewGroup.addView(ViewGroup.java:4822)
at android.widget.PopupWindow.createDecorView(PopupWindow.java:1409)
at android.widget.PopupWindow.preparePopup(PopupWindow.java:1356)
at android.widget.PopupWindow.showAsDropDown(PopupWindow.java:1277)
at android.widget.Editor.showError(Editor.java:565)
at android.widget.Editor.onFocusChanged(Editor.java:1296)
at android.widget.TextView.onFocusChanged(TextView.java:9991)
at android.view.View.handleFocusGainInternal(View.java:6934)
at android.view.View.requestFocusNoSearch(View.java:11546)
at android.view.View.requestFocus(View.java:11520)
at android.view.View.requestFocus(View.java:11487)
at android.view.View.requestFocus(View.java:11429)
at com.syriail.aladdin.VerifyAccountActivity.verify(VerifyAccountActivity.java:107)
at com.syriail.aladdin.VerifyAccountActivity.access$000(VerifyAccountActivity.java:29)
at com.syriail.aladdin.VerifyAccountActivity$1.onClick(VerifyAccountActivity.java:63)
at android.view.View.performClick(View.java:6597)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at org.robolectric.util.Scheduler.runOrQueueRunnable(Scheduler.java:338)
at org.robolectric.util.Scheduler.postDelayed(Scheduler.java:162)
at org.robolectric.util.Scheduler.post(Scheduler.java:141)
at org.robolectric.shadows.ShadowView.post(ShadowView.java:365)
at android.view.View.post(View.java)
at android.view.View.onTouchEvent(View.java:13787)
at android.view.View$GeneratedProxy/243455390.onTouchEvent(Unknown Source)
at org.robolectric.shadows.ShadowView.onTouchEvent(ShadowView.java:219)
at android.view.View.onTouchEvent(View.java)
at android.widget.TextView.onTouchEvent(TextView.java:10064)
at android.view.View.dispatchTouchEvent(View.java:12513)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3052)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3052)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3052)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3052)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3052)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3052)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:440)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1830)
at android.app.Activity.dispatchTouchEvent(Activity.java:3400)
at androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:398)
at org.robolectric.android.internal.LocalUiController.injectMotionEvent(LocalUiController.java:41)
at androidx.test.espresso.base.UiControllerModule$EspressoUiControllerAdapter.injectMotionEvent(UiControllerModule.java:64)
at androidx.test.espresso.action.MotionEvents.sendUp(MotionEvents.java:160)
at androidx.test.espresso.action.MotionEvents.sendUp(MotionEvents.java:137)
at androidx.test.espresso.action.Tap.sendSingleTap(Tap.java:170)
at androidx.test.espresso.action.Tap.access$100(Tap.java:31)
at androidx.test.espresso.action.Tap$1.sendTap(Tap.java:47)
at androidx.test.espresso.action.GeneralClickAction.perform(GeneralClickAction.java:136)
at androidx.test.espresso.ViewInteraction$SingleExecutionViewAction.perform(ViewInteraction.java:356)
at androidx.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:248)
at androidx.test.espresso.ViewInteraction.access$100(ViewInteraction.java:63)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:153)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:150)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at org.robolectric.shadows.ShadowMessageQueue.dispatchMessage(ShadowMessageQueue.java:148)
at org.robolectric.shadows.ShadowMessageQueue.access$200(ShadowMessageQueue.java:38)
at org.robolectric.shadows.ShadowMessageQueue$1.run(ShadowMessageQueue.java:126)
at org.robolectric.util.Scheduler.runOrQueueRunnable(Scheduler.java:338)
at org.robolectric.util.Scheduler.postDelayed(Scheduler.java:162)
at org.robolectric.util.Scheduler.postDelayed(Scheduler.java:151)
at org.robolectric.shadows.ShadowMessageQueue.enqueueMessage(ShadowMessageQueue.java:133)
at android.os.MessageQueue.enqueueMessage(MessageQueue.java)
at android.os.Handler.enqueueMessage(Handler.java:745)
at android.os.Handler.sendMessageAtTime(Handler.java:697)
at android.os.Handler.sendMessageDelayed(Handler.java:667)
at android.os.Handler.post(Handler.java:395)
at androidx.test.espresso.base.BaseLayerModule$1.execute(BaseLayerModule.java:92)
at androidx.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:303)
at androidx.test.espresso.ViewInteraction.desugaredPerform(ViewInteraction.java:161)
at androidx.test.espresso.ViewInteraction.perform(ViewInteraction.java:114)
at com.syriail.aladdin.useraccount.VerifyAccountUnitTest.givenVerificationCodeEmpty_whenUserPressVerify_thenErrorMustAppear(VerifyAccountUnitTest.java:83)
请注意NullPointerException。我不明白为什么!
摆脱下面的代码行,它就会按预期工作。
mVerificationCodeView.requestFocus();
仅当我在本地JVM上运行测试时才会发生此问题,但是当我使用androidTest时,即在真实设备或仿真器上运行测试时,它可以按预期工作,而无需删除上述代码行。像下面的测试
@Test
public void givenVerificationCodeEmpty_whenUserPressVerify_thenErrorMustAppear() {
onView(withId(R.id.verify_account_verify_button)).perform(click());
String error = activityTestRule.getActivity().getString(R.string.error_verification_code_empty);
onView(withId(R.id.verify_code_input)).check(matches(hasErrorText(error)));
}
有关我使用的库的更多信息,这是我的Gradle的一部分
// JUnit 4 framework
testImplementation 'junit:junit:4.12'
/**
* Unit Testing
*/
// Core library
testImplementation 'androidx.test:core:1.0.0'
// AndroidJUnitRunner and JUnit Rules
testImplementation 'androidx.test.ext:junit:1.1.0'
// Robolectric
testImplementation 'org.robolectric:robolectric:4.2'
// Espresso
testImplementation 'androidx.test.espresso:espresso-core:3.1.0'