进度条和Espresso

25

当我在布局中放置了一个ProgressBar,并在运行一些Espresso测试时显示该布局,那么我就会遇到以下问题:

Caused by: android.support.test.espresso.AppNotIdleException: Looped for 1670 iterations over 60 SECONDS. The following Idle Conditions failed .

有什么好的方法可以解决这个问题?找到了一些hackish的东西,但是想要寻找一个好的方法。

5个回答

16

如果在测试开始时ProgressBar不可见,则可以通过自定义的ViewAction来替换Drawable

// Replace the drawable with a static color
onView(isAssignableFrom(ProgressBar.class)).perform(replaceProgressBarDrawable());

// Click a button (that will make the ProgressBar visible)
onView(withText("Show ProgressBar").perform(click());

自定义的 ViewAction

public static ViewAction replaceProgressBarDrawable() {
    return actionWithAssertions(new ViewAction() {
        @Override
        public Matcher<View> getConstraints() {
            return isAssignableFrom(ProgressBar.class);
        }

        @Override
        public String getDescription() {
            return "replace the ProgressBar drawable";
        }

        @Override
        public void perform(final UiController uiController, final View view) {
            // Replace the indeterminate drawable with a static red ColorDrawable
            ProgressBar progressBar = (ProgressBar) view;
            progressBar.setIndeterminateDrawable(new ColorDrawable(0xffff0000));
            uiController.loopMainThreadUntilIdle();
        }
    });
}

1
这对我有用,而且似乎是这里最直接的解决方案。 - MungoRae
2
这个解决方案是最好的,因为它避免了由于测试而修改生产代码的情况。 - pablisco

10

我有同样的问题。我无法找到完全优雅的解决方案,但我将发布我的方法。

我尝试的是在进度条的indeterminateDrawable上进行覆盖。当使用简单的drawable时,不会发生任何动画,并且Espresso测试不会遇到闲置问题。

不幸的是,mainandroidTest被视为相同。我没有找到覆盖我的ProgressBar样式的方法。

现在,我结合了https://gist.github.com/Mauin/62c24c8a53593c0a605e#file-progressbar-javaHow to detect whether android app is running UI test with Espresso中的一些想法。

首先,我创建了两个自定义的ProgressBar类,一个用于调试,另一个用于发布。发布版仅调用超级构造函数,不执行其他操作。调试版本覆盖方法setIndeterminateDrawable。通过这种方式,我可以设置简单的drawable代替动画的drawable。

发布代码:

public class ProgressBar extends android.widget.ProgressBar {

  public ProgressBar(Context context) {
    super(context);
  }

  public ProgressBar(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
  }

}

调试代码:

public class ProgressBar extends android.widget.ProgressBar {

  public ProgressBar(Context context) {
    super(context);
  }

  public ProgressBar(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
  }

  @SuppressWarnings("deprecation")
  @Override
  public void setIndeterminateDrawable(Drawable d) {
    if (isRunningTest()) {
        d = getResources().getDrawable(R.drawable.ic_replay);
    }
    super.setIndeterminateDrawable(d);
  }

  private boolean isRunningTest() {
    try {
        Class.forName("base.EspressoTestBase");
        return true;
    } catch (ClassNotFoundException e) {
        /* no-op */
    }
    return false;
  }

}

正如您所看到的,我还添加了一个检查,以确保我的应用正在运行Espresso测试,而我要搜索的类是我的Espresso测试的基础。

不好的一点是您必须更新所有代码以使用自定义的ProgressBar。但好的一点是,这种解决方案对您的发布代码没有重大影响。


8

我有类似的问题。测试在第一次调用getActivity()时就失败了。因此,ProgressBar的不明确的可绘制对象必须在activity启动后替换。

 Application application = (Application)this.getInstrumentation().getTargetContext().getApplicationContext();
    application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            //not here, it's too early
        }

        @Override
        public void onActivityStarted(Activity activity) {
            //find the progressBar in your activity
            ProgressBar progressBar = ((ProgressBar) activity.findViewById(R.id.progress_bar));
            if(progressBar != null) {
                //replace progress bar drawable as not animated
                progressBar.setIndeterminateDrawable(new ColorDrawable(0xffff0000));
            }
        }

        @Override
        public void onActivityResumed(Activity activity) {

        }

        @Override
        public void onActivityPaused(Activity activity) {

        }

        @Override
        public void onActivityStopped(Activity activity) {

        }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

        }

        @Override
        public void onActivityDestroyed(Activity activity) {

        }
    });

    //Now you can start the activity
    getActivity();

谢谢!当活动创建时出现进度条时非常有用。 - matteoh
这是一个非常棒的解决方案。我只需将此代码包装在静态的@ClassRule中即可,无需更改应用程序代码,这正是我所需要的。 - Gautham C.
不错的解决方案。我只需要将代码移动到onActivityResumed中,因为我的进度条位于由活动加载的片段内。 - Stéphane
这是对我来说最好的解决方案,因为我的进度条都是可见且不确定的。 - David Berry
这有助于防止 Android 5 上的 Espresso bug: "java.lang.RuntimeException: Could not launch intent Intent { Activity } within 45 seconds. Perhaps the main thread has not gone idle within a reasonable amount of time?" 您可以将此代码放入 @BeforeClass 方法中,而且不需要对测试应用程序代码进行任何更改。更多信息:https://jasonfry.co.uk/blog/android-espresso-test-hangs-with-indeterminate-progressbar/ - Mr-IDE

3

根据Thomas R.的解决方案,另一种方法是在测试中更改ProgressBar的drawable,以避免修改生产代码。

示例:

    Activity activity = startActivity();

    // override progress bar infinite animation with a simple image
    ProgressBar progressBar = (ProgressBar) activity.findViewById(R.id.loading_progressbar);
    progressBar.setIndeterminateDrawable(activity.getDrawable(android.R.drawable.ic_lock_lock));

    // click on the button that triggers the display of the progress bar
    onView(withId(R.id.login_button)).perform(click());

1
这个答案可能有点晚。使用espresso,你需要关闭动画。
在你的设备上,进入设置->开发者选项,禁用以下三个设置:
窗口动画缩放、转换动画缩放、动画器持续时间缩放。

https://developer.android.com/training/testing/espresso/setup.html#set-up-environment

在riwnodennyk的Testing progress bar on Android with Espresso中有一个答案。

但是要谨慎使用UIAnimator。

注意:我们建议仅在您的应用程序必须与系统交互以满足关键用例时才使用UI Automator进行测试。由于UI Automator与系统应用程序和UI交互,因此您需要在每次系统更新后重新运行和修复UI Automator测试。此类更新包括Android平台版本升级和Google Play服务的新版本。作为使用UI Automator的替代方法,我们建议添加隔离测试或将大型测试分成一系列小型和中型测试。特别是专注于一次测试一个应用程序间通信的部分,例如向其他应用程序发送信息并响应意图结果。Espresso-Intents工具可以帮助您编写这些较小的测试。

https://developer.android.com/training/testing/fundamentals.html#large-tests


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接