Android Espresso IdlingResource不等待ViewPager开始滚动

时间:2017-01-07 02:16:33

标签: android android-espresso

我正在测试ViewPager应用程序。我开始使用ViewPagerIdlingResource,然后执行swipeLeft(),但在ViewPager甚至可以开始滚动onView()之前。调用check()并且测试失败。 这是我的ViewPagerIdlingResource,我几乎从vaughandroid

复制了
public class ViewPagerIdlingResource implements IdlingResource {

  private final String mName;

  private boolean mIdle = true; // Default to idle since we can't query the scroll state.

  private ResourceCallback mResourceCallback;

  private boolean anyPageScrolledHappened = false;

  public ViewPagerIdlingResource(ViewPager viewPager, String name) {
    Log.i("ATAG", "ViewPagerIdlingResource constructor");
    viewPager.addOnPageChangeListener(new ViewPagerListener());
    mName = name;
  }

  @Override
  public String getName() {
    return mName;
  }

  @Override
  public boolean isIdleNow() {
    Log.i("ATAG", "isIdleNow: "+mIdle);
    return mIdle;
  }

  @Override
  public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
    Log.i("ATAG", "ViewPagerIdlingResource registerIdleTransitionCallback");
    mIdle = true;
    mResourceCallback = resourceCallback;
  }

  public void setIdle (boolean idle) {
    Log.i("ATAG", "setIdle: false and anyPageScrolledHappened = "+anyPageScrolledHappened);
    if (!anyPageScrolledHappened && false == idle) {
      mIdle = false;
    }
  }

  private class ViewPagerListener extends ViewPager.SimpleOnPageChangeListener {

    @Override
    public void onPageScrollStateChanged(int state) {
      anyPageScrolledHappened = true;
      Log.i("ATAG", "ViewPager OnPageScrollStateChanged: ScrollState: " + state);
      mIdle = (state == ViewPager.SCROLL_STATE_IDLE
      // Treat dragging as idle, or Espresso will block itself when swiping.
        || state == ViewPager.SCROLL_STATE_DRAGGING);
      if (mIdle && mResourceCallback != null) {
        Log.i("ATAG", "OnTransitionToIdle");
      mResourceCallback.onTransitionToIdle();
      }
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
      Log.i("ATAG", "ViewPager OnPageScrolled:           ScrollState: " + "none");
    }

    @Override
    public void onPageSelected(int position) {
      Log.i("ATAG", "ViewPager OnPageSelected:           ScrollState: " + "none");
    }
  }
} 

这是我的考验。

@RunWith(AndroidJUnit4.class)
public class StraightLineTest {
  private ViewPagerIdlingResource idlingResource;

  private static final String shmi_s   = "Shmi Skywalker";
  private static final String anakin_s = "Anakin Skywalker";
  private static final String leia_o   = "Leia Organa";
  private static final String jacen_s  = "Jacen Solo";
  private static final String allana_s = "Allana Solo";

  @Rule
  public IntentsTestRule<MainActivity> mActivityRule =
    new IntentsTestRule(MainActivity.class, true, false);

  @After
  public void tearDownIdlingResource () {
    unregisterIdlingResources(idlingResource);
  }

  @Test
  public void firstSwipe () {

    Activity activity = startActivity();

    idlingResource = new ViewPagerIdlingResource((ViewPager)activity.
      findViewById(R.id.view_pager), "VPIR_0");
    registerIdlingResources(idlingResource);


    onView(isRoot()).perform(swipeLeft());
    //idlingResource.setIdle(false);
    //waitForViewPagerResponse(1000);

    onView(allOf(withId(R.id.character_name),withText(anakin_s))).
    check(matches(isCompletelyDisplayed()));
  }

  @Test
  public void fifthSwipe () {
    Activity activity = startActivity();

    idlingResource = new ViewPagerIdlingResource((ViewPager)activity.
      findViewById(R.id.view_pager), "VPIR_0");
    registerIdlingResources(idlingResource);

    onView(isRoot()).perform(swipeLeft());
    onView(allOf(withId(R.id.character_name),withText(anakin_s))).
      check(matches(isCompletelyDisplayed()));

    onView(isRoot()).perform(swipeLeft());
    onView(allOf(withId(R.id.character_name),withText(leia_o))).
      check(matches(isCompletelyDisplayed()));

    onView(isRoot()).perform(swipeLeft());
    onView(allOf(withId(R.id.character_name),withText(jacen_s))).
      check(matches(isCompletelyDisplayed()));

    onView(isRoot()).perform(swipeLeft());
    onView(allOf(withId(R.id.character_name),withText(allana_s))).
      check(matches(isCompletelyDisplayed()));
  }
  private MainActivity startActivity() {
    return mActivityRule.launchActivity(null);
  }

  public static void waitForViewPagerResponse(long millis) {
    final long startTime = System.currentTimeMillis();
    final long endTime = startTime + millis;
    do {}
    while (System.currentTimeMillis() < endTime);
  }
}

因此,第五个Swipe()测试总是通过。

firstSwipe()测试通常会失败。当firstSwipe()失败时,不会调用ViewPageListener内部的任何Log方法。如果我在swipeLeft()调用之后调用waitForViewPagerResponse(),则调用ViewPagerListener日志方法,并且测试通过。

如果我在swipeLeft()之后通过调用setIdle(false)将IdlingResource的mIdle设置为false,那么测试就会一直存在,直到它超时并且没有ViewPagerListener日志消息。

我试图找到一些方法将mIdle设置为false,直到它第一次开始滚动,然后它会在onPageScrollStateChanged()方法中将自己设置为true。但测试只是等待,滚动永远不会发生,检查永远不会发生,它只是超时。我得出结论,当isIdleNow()返回false时,ViewPager无法开始滚动。为什么isIdleNow()会影响ViewPager?我认为这样做是因为如果我只是让时间与waitForViewPagerResponse()一起传递,那么我最终会得到回调到ViewPagerListener。

有没有人有一个对ViewPagers没有这个问题的IdlingResource?我是否错误地实施了此IdlingResource?

这是github上的项目。 https://github.com/flocela/PagerAdapter

修改 这是失败时的日志(.setIdle()和waitForViewPagerResponse()仍被注释掉的情况。)我想要做的是执行快速扫描&#39;动作发生,但在ViewPager可以滚动之前(由ViewPagerListener日志指示),检查完成并且测试失败。

I / ATAG:ViewPagerIdlingResource构造函数
I / ATAG:ViewPagerIdlingResource registerIdleTransitionCallback
I / ATAG:isIdleNow:是的 D / InputManagerEventInjectionStrategy:使用输入管理器创建注入策略 I / ATAG:isIdleNow:是的 I / ATAG:isIdleNow:是的 I / ViewInteraction:执行快速刷卡&#39;视图上的操作是根视图。 I / ATAG:isIdleNow:是的 I / ATAG:isIdleNow:true (重复一段时间)
D / LifecycleMonitor:生命周期状态变化:--- .---。MainActivity@d771792 in:PAUSED
I / TestRunner:失败:firstSwipe(--- .---。StraightLineWIRTest)
I / TestRunner:-----开始异常----- I / TestRunner:android.support.test.espresso.base.DefaultFailureHandler $ AssertionFailedWithCauseError:&#39;至少100%的视图区域显示给用户。&#39;与所选视图不匹配。
预期:至少100%的视图区域会显示给用户 得到:&#34; AppCompatTextView {id = 2131427414,res-name = character_name,visibility = VISIBLE,(很多东西),x = 0.0,y = 0.0,text = Anakin Skywalker,输入 - type = 0,ime-target = false,has-links = false}&#34;

修改 这是我在swipeLeft()之后调用idlingResource.setIdle(false)时的日志输出。 waitForViewPagerResponse()仍然被注释掉了。我的观点是因为isIdleNow()返回false,因此ViewPager不会滚动。为什么会这样?

I / ATAG:ViewPagerIdlingResource构造函数
I / ATAG:ViewPagerIdlingResource registerIdleTransitionCallback
I / ATAG:isIdleNow:是的 D / InputManagerEventInjectionStrategy:使用输入管理器创建注入策略 I / ATAG:isIdleNow:是的 I / ATAG:isIdleNow:是的 I / ViewInteraction:执行快速刷卡&#39;视图上的操作是根视图 I / ATAG:isIdleNow:是的 I / ATAG:isIdleNow:true (重复一段时间)
I / ATAG:setIdle:false和anyPageScrolledHappened = false
I / ATAG:isIdleNow:false
I / ATAG:isIdleNow:false
W / IdlingPolicy:这些资源不是空闲的:[VPIR_0] (2行重复)
I / ATAG:isIdleNow:false (2行重复)
D / LifecycleMonitor:生命周期状态变化:--- .---。MainActivity@d771792 in:PAUSED
I / TestRunner:失败:firstSwipe(flobee.pageradapterex.StraightLineWIRTest)
I / TestRunner:-----开始异常----- I / TestRunner:android.support.test.espresso.IdlingResourceTimeoutException:等待[VPIR_0]空闲超时

0 个答案:

没有答案