Android应用运行Espresso测试时出现Cloud Firestore 24.1.2内部错误
问题现象
应用正常运行时数据加载无任何问题,仅在运行Espresso测试校验约会应用的匹配卡片是否存在时触发报错。使用本地模拟数据运行相同测试时无异常,将应用接入Firebase后就会出现该错误。
核心报错提示:java.lang.RuntimeException: Internal error in Cloud Firestore (24.1.2).
本次运行的测试代码
public void matchesCardExists(){ onView(withId(R.id.name)).perform(replaceText("Bill")); onView(withId(R.id.email)).perform(replaceText("test@gmail.com")); onView(withId(R.id.user_name)).perform(replaceText("bigbill")); onView(withId(R.id.description)).perform(replaceText("This is a test")); onView(withId(R.id.occupation)).perform(replaceText("I work at test")); onView(withId(R.id.dateButton)).perform(click()); onView(withClassName(Matchers.equalTo(DatePicker.class.getName()))) .perform(PickerActions.setDate(2000, 2 + 1, 5)); onView(withId(android.R.id.button1)).perform(click()); onView(withId(R.id.submitButton)).perform(click()); openActionBarOverflowOrOptionsMenu(ApplicationProvider.getApplicationContext()); onView(withText("Matches")).perform(click()); onView(isRoot()).perform(HelpersViewMatcher.waitView(withText("Cool Guy Mike"), 100000)); onView(withRecyclerView(R.id.recycler_view).atPosition(0)).check(matches(hasDescendant(withText("Cool Guy Mike")))); }
测试逻辑说明
测试会填写注册表单,提交后跳转至包含匹配Fragment的标签页Activity,匹配Fragment中展示的卡片数据从Cloud Firestore加载,测试校验RecyclerView第0位的卡片是否包含字符串“Cool Guy Mike”。
报错堆栈
Firebase返回的堆栈跟踪
java.lang.NullPointerException at java.util.Objects.requireNonNull(Objects.java:203) at com.example.datingapp.RecyclerViewMatcher$1.matchesSafely(RecyclerViewMatcher.java:56) at com.example.datingapp.RecyclerViewMatcher$1.matchesSafely(RecyclerViewMatcher.java:30) at org.hamcrest.TypeSafeMatcher.matches(TypeSafeMatcher.java:67) at androidx.test.espresso.base.ViewFinderImpl$MatcherPredicateAdapter.apply(ViewFinderImpl.java:1) at androidx.test.espresso.core.internal.deps.guava.collect.Iterators$5.computeNext(Iterators.java:3) at androidx.test.espresso.core.internal.deps.guava.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:2) at androidx.test.espresso.core.internal.deps.guava.collect.AbstractIterator.hasNext(AbstractIterator.java:5) at androidx.test.espresso.base.ViewFinderImpl.getView(ViewFinderImpl.java:7) at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:5) at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:1) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Android Studio中捕获的错误信息
androidx.test.espresso.PerformException: Error performing 'single click - At Coordinates: 1082, 465 and precision: 16, 16' on view 'Animations or transitions are enabled on the target device. an instance of android.widget.TextView and view.getText() with or without transformation to match: is "Matches"'. at androidx.test.espresso.PerformException$Builder.build(PerformException.java:1) at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:9) at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:7) at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:8) at androidx.test.espresso.ViewInteraction.desugaredPerform(ViewInteraction.java:11) at androidx.test.espresso.ViewInteraction.perform(ViewInteraction.java:4) at com.example.datingapp.MainActivityTest.matchesCardExists(MainActivityTest.java:265) ... 29 trimmed Caused by: java.lang.RuntimeException: Internal error in Cloud Firestore (24.1.2). at com.google.firebase.firestore.util.AsyncQueue.lambda$panic$3(AsyncQueue.java:539) at com.google.firebase.firestore.util.-$$Lambda$AsyncQueue$jx84dqgUsF4ojecSMurRqFLFD1Y.run(Unknown Source:2) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at androidx.test.espresso.base.Interrogator.loopAndInterrogate(Interrogator.java:14) at androidx.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:8) at androidx.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:1) at androidx.test.espresso.base.UiControllerImpl.loopMainThreadForAtLeast(UiControllerImpl.java:8) at androidx.test.espresso.action.Tap$1.sendTap(Tap.java:6) at androidx.test.espresso.action.GeneralClickAction.perform(GeneralClickAction.java:6) at androidx.test.espresso.ViewInteraction$SingleExecutionViewAction.perform(ViewInteraction.java:2) at androidx.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:22) at androidx.test.espresso.ViewInteraction.access$100(ViewInteraction.java:1) at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:2) at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:1) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) Caused by: java.lang.NoSuchMethodError: No static method registerDefaultInstance(Ljava/lang/Class;Lcom/google/protobuf/GeneratedMessageLite;)V in class Lcom/google/protobuf/GeneratedMessageLite; or its super classes (declaration of 'com.google.protobuf.GeneratedMessageLite' appears in /data/app/com.example.datingapp.test-LB1xq3vHsZYBNdA8gmmVkQ==/base.apk) at com.google.firestore.v1.ListenRequest.<clinit>(ListenRequest.java:873) at com.google.firestore.v1.ListenRequest.getDefaultInstance(ListenRequest.java:878) at com.google.firestore.v1.FirestoreGrpc.getListenMethod(FirestoreGrpc.java:384) at com.google.firebase.firestore.remote.WatchStream.<init>(WatchStream.java:61) at com.google.firebase.firestore.remote.Datastore.createWatchStream(Datastore.java:131) at com.google.firebase.firestore.remote.RemoteStore.<init>(RemoteStore.java:167) at com.google.firebase.firestore.core.MemoryComponentProvider.createRemoteStore(MemoryComponentProvider.java:78) at com.google.firebase.firestore.core.ComponentProvider.initialize(ComponentProvider.java:143) at com.google.firebase.firestore.core.FirestoreClient.initialize(FirestoreClient.java:272) at com.google.firebase.firestore.core.FirestoreClient.lambda$new$0$FirestoreClient(FirestoreClient.java:109) at com.google.firebase.firestore.core.-$$Lambda$FirestoreClient$Eq-cAcb1C1mM4tyiJsLJXZ13tyU.run(Unknown Source:8) at com.google.firebase.firestore.util.AsyncQueue.lambda$enqueue$2(AsyncQueue.java:441) at com.google.firebase.firestore.util.-$$Lambda$AsyncQueue$Y9GO7zO2DX6MzQJ5TbKtKW_NzO0.call(Unknown Source:2) at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor.lambda$executeAndReportResult$1(AsyncQueue.java:327) at com.google.firebase.firestore.util.-$$Lambda$AsyncQueue$SynchronizedShutdownAwareExecutor$pKSAgg-ozJ8RbUveSl-44aUfFQw.run(Unknown Source:4) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor$DelayedStartFactory.run(AsyncQueue.java:234) at java.lang.Thread.run(Thread.java:919)
根因定位
从堆栈最底层的错误可以定位核心问题:
- 首要原因是Protobuf依赖版本冲突:Cloud Firestore 24.1.2依赖的高版本protobuf-javalite库中存在
registerDefaultInstance方法,但测试APK打包时被其他依赖引入的低版本protobuf库覆盖,导致Firestore初始化实时数据监听流时找不到对应方法,直接抛出内部错误。 - Firestore崩溃后匹配列表数据无法加载,自定义的RecyclerViewMatcher没有做空值容错,在item不存在时直接调用
Objects.requireNonNull触发空指针。 - 测试设备未关闭系统动画,可能导致Espresso点击溢出菜单的坐标偏移,加剧操作失败的概率。
修复方案
- 强制对齐Protobuf依赖版本:在app模块的build.gradle中添加依赖强制规则,使用和Firestore 24.1.2匹配的protobuf版本:
configurations.all { resolutionStrategy.force 'com.google.protobuf:protobuf-javalite:3.19.2' }
- 排查项目中所有第三方依赖,若有依赖引入了低版本protobuf,直接排除其传递的protobuf依赖,避免版本覆盖。
- 修复自定义RecyclerViewMatcher的逻辑:在
matchesSafely方法中添加空判断,RecyclerView未加载、指定位置无item时直接返回匹配失败,不要直接调用requireNonNull。 - 测试前关闭测试设备的所有系统动画:将窗口动画缩放、过渡动画缩放、动画程序时长缩放全部调整为0,避免动画干扰Espresso的视图操作和判断。
内容的提问来源于stack exchange,提问作者Calas
相关产品推荐
相关产品推荐

