升级Android Material版本致Firebase测试失败,但本地测试正常
Material组件升级1.6.0-alpha01后FTL Espresso测试失败问题分析与解决
核心问题
将com.google.android.material:material从1.5.0升级到1.6.0-alpha01后,针对包含MaterialAutoCompleteTextView的TextInputLayout的FTL测试出现NoMatchingRootException,表现为下拉菜单未弹出,但本地测试及旧版本FTL环境可正常通过。
可能原因
- 下拉菜单根视图类型变更:1.6.0-alpha01重构了ExposedDropdownMenu的实现,原有的
PopupWindow$PopupViewContainer根视图被替换为其他类型,导致isPlatformPopup()匹配失败。 - FTL环境动画延迟:FTL测试环境的动画渲染速度慢于本地,新版本组件的下拉动画未完成时,Espresso就开始查找子项。
- 点击触发逻辑变更:新版本中点击
TextInputLayout触发下拉的逻辑被调整,需要直接点击MaterialAutoCompleteTextView才能弹出菜单。
解决方案
1. 调整根视图匹配器
自定义匹配器适配新版本的下拉菜单根视图,替代isPlatformPopup():
public static Matcher<Root> isMaterialDropdownRoot() { return new TypeSafeMatcher<Root>() { @Override public void describeTo(Description description) { description.appendText("匹配Material下拉菜单根视图"); } @Override protected boolean matchesSafely(Root root) { String decorViewClassName = root.getDecorView().getClass().getName(); // 匹配Material组件下拉菜单的容器类 return decorViewClassName.contains("PopupViewContainer") && !root.isDialog() && root.hasWindowFocus(); } }; }
修改测试代码:
onView(withId(R.id.textInputLayout)).perform(scrollTo(), click()) onView(withText("Dropdown Name")) .inRoot(isMaterialDropdownRoot()) .perform(click())
2. 添加显式等待逻辑
针对FTL环境的延迟问题,添加等待视图出现的逻辑:
public static ViewAction waitForView(final Matcher<View> matcher, long timeoutMs) { return new ViewAction() { @Override public Matcher<View> getConstraints() { return isAssignableFrom(View.class); } @Override public String getDescription() { return "等待视图出现,超时时间:" + timeoutMs + "ms"; } @Override public void perform(UiController uiController, View view) { uiController.loopMainThreadUntilIdle(); long endTime = System.currentTimeMillis() + timeoutMs; do { for (View child : TreeIterables.breadthFirstViewTraversal(view)) { if (matcher.matches(child)) return; } uiController.loopMainThreadForAtLeast(50); } while (System.currentTimeMillis() < endTime); throw new PerformException.Builder() .withActionDescription(getDescription()) .withCause(new TimeoutException("视图未在超时时间内出现")) .build(); } }; }
测试代码中添加等待:
onView(withId(R.id.textInputLayout)).perform(scrollTo(), click()) // 等待下拉菜单项出现 onView(isRoot()).perform(waitForView(withText("Dropdown Name"), 3000)) onView(withText("Dropdown Name")) .inRoot(isPlatformPopup()) .perform(click())
3. 直接点击MaterialAutoCompleteTextView
修改测试逻辑,直接点击输入框而非父布局:
onView(withId(R.id.autoCompleteTextView)).perform(scrollTo(), click()) onView(withText("Dropdown Name")) .inRoot(isPlatformPopup()) .perform(click())
4. 禁用测试环境动画
在build.gradle中全局禁用动画:
android { testOptions { animationsDisabled = true } }
或在测试类中通过命令行禁用系统动画:
@Before public void setup() { UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); try { device.executeShellCommand("settings put global window_animation_scale 0"); device.executeShellCommand("settings put global transition_animation_scale 0"); device.executeShellCommand("settings put global animator_duration_scale 0"); } catch (IOException e) { e.printStackTrace(); } }
内容的提问来源于stack exchange,提问作者cchman
相关产品推荐
相关产品推荐

