【问题标题】:ProgressBars and Espresso进度条和浓缩咖啡
【发布时间】:2015-10-22 19:30:07
【问题描述】:

当我在运行某些 espresso 测试时显示的布局中有一个 ProgressBar - 然后我遇到:

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

有什么好的方法可以解决这个问题?发现了一些骇人听闻的东西,但正在寻找一种好方法

【问题讨论】:

    标签: android android-espresso


    【解决方案1】:

    如果在测试开始时ProgressBar 不可见,则可以将Drawable 替换为自定义ViewAction

    // 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();
            }
        });
    }
    

    【讨论】:

    • 这对我有用,这似乎是这里最直接的解决方案。
    • 这个解决方案是最好的,因为避免了因为测试而不得不修改生产代码
    【解决方案2】:

    我也有同样的问题。我想不出一个完全优雅的解决方案,但我也会发布我的方法。

    我试图做的是覆盖 ProgressBar 上的indeterminateDrawable。当有一个简单的 drawable 时,没有动画发生,并且 Espresso 测试没有遇到 Idle 问题。

    很遗憾,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而不是动画。

    发布代码:

    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。但好在你的发布代码对这个解决方案没有重大影响。

    【讨论】:

      【解决方案3】:

      我有类似的问题。早在第一次调用getActivity()时测试就失败了。所以在Activity开始后,ProgressBar的不定drawable必须被替换掉。

       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();
      

      【讨论】:

      • 谢谢!在创建activity时出现进度条时非常有用。
      • 这是一个很棒的解决方案。我只是把这段代码包装在一个静态的@ClassRule 中。无需更改应用代码,这正是我想要的。
      • 不错的解决方案。我只需要在 onActivityResumed 而不是 onActivityStarted 中移动代码,因为我的进度条位于 Activity 加载的片段内。
      • 这是最适合我的解决方案,因为我的进度条都是可见且不确定的。
      • 这有助于防止 Android 5 上的 Espresso 错误:"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 方法中,并且不需要对被测应用代码进行任何更改。更多信息:jasonfry.co.uk/blog/…
      【解决方案4】:

      基于Thomas R. solution,另一种方法是在测试中更改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());
      

      【讨论】:

      • 你拯救了我的一天
      【解决方案5】:

      这个答案可能会迟到。使用浓缩咖啡,您必须关闭动画。

      在您的设备上,在“设置”>“开发者选项”下,禁用 以下3个设置:

      Window 动画比例、Transition 动画比例、Animator 持续时间比例

      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平台版本升级和新版本 谷歌播放服务。作为使用 UI Automator 的替代方案,我们 建议添加密封测试或将大型测试分成一个 一套中小型测试。尤其要重点测试一个 一次应用间通信,例如发送 向其他应用程序提供信息并响应意图结果。这 Espresso-Intents 工具可以帮助您编写这些较小的测试。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多