如何用Android Espresso测试ProgressDialog的显示与消失?
Android Espresso测试:验证ProgressDialog在数据加载完成后消失
推荐方案:使用IdlingResource(官方最佳实践)
Espresso默认仅等待主线程空闲,但后台数据加载(如API请求、Room操作)属于异步任务,不会自动触发Espresso的等待机制。通过注册IdlingResource,可以让Espresso感知异步任务的状态,直到任务完成后再执行断言。
1. 实现自定义IdlingResource
这个资源会监听数据加载的状态,当加载完成时通知Espresso:
public class DataLoadingIdlingResource implements IdlingResource { private volatile ResourceCallback callback; private boolean isLoading = true; @Override public String getName() { return DataLoadingIdlingResource.class.getName(); } @Override public boolean isIdleNow() { return !isLoading; } @Override public void registerIdleTransitionCallback(ResourceCallback callback) { this.callback = callback; } // 外部调用此方法更新加载状态 public void setLoading(boolean loading) { this.isLoading = loading; if (!loading && callback != null) { callback.onTransitionToIdle(); } } }
2. 在测试类中注册/注销IdlingResource
结合ViewModel(或Repository)的加载状态LiveData,同步IdlingResource的状态:
@RunWith(AndroidJUnit4.class) public class DataDownloadTest { @Rule public ActivityScenarioRule<MainActivity> activityRule = new ActivityScenarioRule<>(MainActivity.class); private DataLoadingIdlingResource idlingResource; @Before public void setUp() { activityRule.getScenario().onActivity(activity -> { // 获取ViewModel实例 MyViewModel viewModel = new ViewModelProvider(activity).get(MyViewModel.class); idlingResource = new DataLoadingIdlingResource(); // 观察加载状态,同步到IdlingResource viewModel.getIsLoading().observe(activity, isLoading -> { idlingResource.setLoading(isLoading); }); }); // 注册到Espresso的空闲资源注册表 IdlingRegistry.getInstance().register(idlingResource); } @After public void tearDown() { if (idlingResource != null) { IdlingRegistry.getInstance().unregister(idlingResource); } } @Test public void testProgressDialogFlow() { // 1. 验证下载按钮可见 onView(withText("Download data")).check(matches(isDisplayed())); // 2. 点击下载按钮 onView(withText("Download data")).perform(click()); // 3. 验证ProgressDialog显示 onView(withText("Downloading data")).check(matches(isDisplayed())); // 4. 验证ProgressDialog消失(Espresso会自动等待加载完成) onView(withText("Downloading data")).check(matches(not(isDisplayed()))); // 如果对话框被销毁,也可以用:onView(withText("Downloading data")).check(doesNotExist()); } }
备选方案:带超时的等待工具方法
如果暂时无法集成IdlingResource,可以使用带超时的轮询方法替代你的无限循环,避免测试无限挂起:
public static void waitForViewToBeGone(Matcher<View> viewMatcher, long timeoutMillis) { long endTime = System.currentTimeMillis() + timeoutMillis; while (System.currentTimeMillis() < endTime) { try { onView(viewMatcher).check(matches(not(isDisplayed()))); return; } catch (AssertionError | NoMatchingViewException e) { // 视图仍存在,继续等待 try { Thread.sleep(100); } catch (InterruptedException ignored) {} } } // 超时后抛出断言错误 onView(viewMatcher).check(matches(not(isDisplayed()))); }
在测试中调用:
// 步骤4:等待对话框消失,超时5秒 waitForViewToBeGone(withText("Downloading data"), 5000);
为什么你的临时方案不推荐
- 无限循环无超时,若对话框未正常消失,测试会永久挂起
- 轮询效率低,且不符合Espresso的异步等待设计理念
- 没有利用Espresso的内置等待机制,容易出现不稳定的测试结果
内容的提问来源于stack exchange,提问作者Bhavesh Achhada
相关产品推荐
相关产品推荐

