Android Espresso - 如何确认 swipeLeft() 确实滑动了?

Android Espresso - How to confirm swipeLeft() actually swiped?

我有一个 viewpager,其中至少有 4 个元素,但它是动态的,可以有超过 4 个元素。我想测试我是否能够至少滑动 pager 4 次。该测试正在测试 viewPager 至少有 4 个我可以滑动到的元素。我怎样才能做到这一点。这是我目前所拥有的:

 int numOfPages = 4;
        do {
            onView(withId(R.id.pager)), matches(isDisplayed());
            onView(withId(R.id.pager))
                    .perform(swipeLeft());
            numOfPages--;
        } while (numOfPages > 0);

但这只是向左滑动至少 4 次。如果我将 numOfPages 更改为 15,它只会尝试滑动 15 次而不会引发任何错误。那么我怎么知道测试是否成功? viewpager 中的 Fragments 不可点击,它们只显示图像。

您可以使用自定义匹配器检查 viewPager.getCurrentItem() 是否符合您的期望:

@Test
public void swipeFirstPages() {
  int numPages = 4;
  for (int i = 0; i < numPages; i++) {
    // Check the ViewPager is in page i
    onView(withId(R.id.pager)).check(matches(inPage(i)));

    if (i < numPages - 1) { // perform swipe if not on last page
      onView(withId(R.id.pager)).perform(swipeLeft());
      SystemClock.sleep(800);
    }
  }
}

inPage 匹配器中使用的代码:

/**
 * Returns a matcher that matches {@link ViewPager}s based on currentItem property value.
 *
 * @param page {@link Matcher} of ViewPager's currentItem
 */
@NonNull
public static Matcher<View> inPage(final int page) {

  return new BoundedMatcher<View, ViewPager>(ViewPager.class) {

    @Override
    public void describeTo(final Description description) {
      description.appendText("in page: " + page);
    }

    @Override
    public boolean matchesSafely(final ViewPager viewPager) {
      return viewPager.getCurrentItem() == page;
    }
  };
}

如果您想在每次滑动后避免 SystemClock.sleep,您可以使用

如果您只关心页数,那么编写断言有 n 或多于 n 页的 ViewMatcher 是微不足道的:

fun withNumberOfPages(numberOfPages: Matcher<Int>): Matcher<View> {

    return object : BoundedMatcher<View, ViewPager>(ViewPager::class.java) {
        override fun describeTo(description: Description) {
            description.appendText("with ")
            numberOfPages.describeTo(description)
            description.appendText("number of pages")

        }

        override fun matchesSafely(viewPager: ViewPager): Boolean {
            return numberOfPages.matches(viewPager.adapter?.count ?: -1)
        }
    }
}

如果你真的想知道寻呼机是否 "swipeable" 至少 4 次,我们可以添加另一个匹配器,断言每次滑动后寻呼机在第 n 页:

fun withSelectedPage(selection: Int): Matcher<View> {
    return object : BoundedMatcher<View, ViewPager>(ViewPager::class.java) {
        private var actualSelection = -1

        override fun describeTo(description: Description) {
            if (actualSelection != -1) {
                description.appendText("with $selection page selected")
                description.appendText("\n But page $actualSelection was selected")
            }
        }

        override fun matchesSafely(viewPager: ViewPager): Boolean {
            actualSelection = viewPager.currentItem
            return selection == actualSelection
        }
    }
}

用法如下:

onView(withId(R.id.pager)).check(matches(withNumberOfPages(Matchers.greaterThan(4))))

&&

onView(withId(R.id.pager)).check(matches(withSelectedPage(1)))

但这里的另一个哲学问题是它实际上测试了什么吗?可能是。但根据实际业务需求,它可能实际上没有帮助。

用户如何知道刷卡成功?他们可能在屏幕上看到了一些东西。 espresso 的想法是以类似的方式进行测试。如果对页面上的内容有真正的兴趣,那么一切都归结为用于测试的密封环境。如果您无法控制测试接收到的数据,那么您就没有进行太多测试。如果您可以模拟传入的数据,那么 vewpager 将始终设置为相同数量的页面,您将知道每个页面包含什么。这将使您的测试更加独立、确定并提供实际价值。