【问题标题】:How to count RecyclerView items with Espresso如何使用 Espresso 计算 RecyclerView 项目
【发布时间】:2016-04-04 10:07:55
【问题描述】:

使用 Espresso 和 Hamcrest,

如何计算 recyclerView 中可用的项目数?

示例:我想检查 5 个项目是否显示在特定的 RecyclerView 中(必要时滚动)。

【问题讨论】:

标签: android android-recyclerview android-espresso hamcrest


【解决方案1】:

这里是一个查看 RecyclerView 项目计数的示例 ViewAssertion

public class RecyclerViewItemCountAssertion implements ViewAssertion {
  private final int expectedCount;

  public RecyclerViewItemCountAssertion(int expectedCount) {
    this.expectedCount = expectedCount;
  }

  @Override
  public void check(View view, NoMatchingViewException noViewFoundException) {
    if (noViewFoundException != null) {
        throw noViewFoundException;
    }

    RecyclerView recyclerView = (RecyclerView) view;
    RecyclerView.Adapter adapter = recyclerView.getAdapter();
    assertThat(adapter.getItemCount(), is(expectedCount));
  }
}

然后使用这个断言

onView(withId(R.id.recyclerView)).check(new RecyclerViewItemCountAssertion(5));

我已经开始编写一个库,它应该可以让 espresso 和 uiautomator 的测试更加简单。这包括用于 RecyclerView 操作和断言的工具。 https://github.com/nenick/espresso-macchiato 参见例如带有方法 assertItemCountIs(int) 的 EspRecyclerView

【讨论】:

  • 此测试始终通过。我不认为它工作正常。
  • adapter.getItemCount() 即将为空。请告诉我原因。
  • @AdamHurwitz 很多人已经确认这项工作,但请说明你的情况,它总是通过。
  • @VikashKumar 它返回 null 还是零?空值应该是不可能的。但也许它的时间问题和您的适配器在检查时有零项?经常在使用后台任务时发生。
  • 如何计算物品数量,而不是如何检查有X物品?
【解决方案2】:

在@Stephane's answer 中添加一点语法糖。

public class RecyclerViewItemCountAssertion implements ViewAssertion {
    private final Matcher<Integer> matcher;

    public static RecyclerViewItemCountAssertion withItemCount(int expectedCount) {
        return withItemCount(is(expectedCount));
    }

    public static RecyclerViewItemCountAssertion withItemCount(Matcher<Integer> matcher) {
        return new RecyclerViewItemCountAssertion(matcher);
    }

    private RecyclerViewItemCountAssertion(Matcher<Integer> matcher) {
        this.matcher = matcher;
    }

    @Override
    public void check(View view, NoMatchingViewException noViewFoundException) {
        if (noViewFoundException != null) {
            throw noViewFoundException;
        }

        RecyclerView recyclerView = (RecyclerView) view;
        RecyclerView.Adapter adapter = recyclerView.getAdapter();
        assertThat(adapter.getItemCount(), matcher);
    }
}

用法:

    import static your.package.RecyclerViewItemCountAssertion.withItemCount;

    onView(withId(R.id.recyclerView)).check(withItemCount(5));
    onView(withId(R.id.recyclerView)).check(withItemCount(greaterThan(5)));
    onView(withId(R.id.recyclerView)).check(withItemCount(lessThan(5)));
    // ...

【讨论】:

  • 太棒了。我建议将它加入到 espresso 中,因为没有这样的核心功能真的很奇怪。
  • 不再起作用。显示一个白屏,并且没有收集更多响应,最终未通过测试。
【解决方案3】:

完成 nenick 回答并提供更灵活的解决方案来测试项目 cout 是否大于、小于...

public class RecyclerViewItemCountAssertion implements ViewAssertion {

    private final Matcher<Integer> matcher;

    public RecyclerViewItemCountAssertion(int expectedCount) {
        this.matcher = is(expectedCount);
    }

    public RecyclerViewItemCountAssertion(Matcher<Integer> matcher) {
        this.matcher = matcher;
    }

    @Override
    public void check(View view, NoMatchingViewException noViewFoundException) {
        if (noViewFoundException != null) {
            throw noViewFoundException;
        }

        RecyclerView recyclerView = (RecyclerView) view;
        RecyclerView.Adapter adapter = recyclerView.getAdapter();
        assertThat(adapter.getItemCount(), matcher);
    }

}

用法:

onView(withId(R.id.recyclerView)).check(new RecyclerViewItemCountAssertion(5));
onView(withId(R.id.recyclerView)).check(new RecyclerViewItemCountAssertion(greaterThan(5));
onView(withId(R.id.recyclerView)).check(new RecyclerViewItemCountAssertion(lessThan(5));
// ...

【讨论】:

    【解决方案4】:

    经过验证的答案有效,但我们可以用一条线解决这个问题,而无需适配器意识:

    onView(withId(R.id.your_recycler_view_id)).check(matches(hasChildCount(2)))
    

    将your_recycler_view_id 替换为您的ID,将2 替换为要声明的号码。

    【讨论】:

    • IDE 说:无法解析方法hasChildCount(int)
    • 别忘了导入androidx.test.espresso.matcher.ViewMatchers.hasChildCount
    • 这个是统计可以显示的项目总数(即适配器的getItemCount())还是统计RecyclerView中当前回收视图的数量?
    • 好问题。可能不是适配器的getItemCount()。因此,此解决方案仅在您可以拥有有限数量的项目而不是在所有设备上时才可行。
    【解决方案5】:

    基于@Sivakumar Kamichetty 的回答:

    1. 从内部类中访问变量“COUNT”,需要声明为 final。
    2. 不必要的线路:COUNT = 0;
    3. 将COUNT 变量转移到一个元素数组中。
    4. 变量result 是不必要的。

    不好,但可以:

    public static int getCountFromRecyclerView(@IdRes int RecyclerViewId) {
        final int[] COUNT = {0};
        Matcher matcher = new TypeSafeMatcher<View>() {
            @Override
            protected boolean matchesSafely(View item) {
                COUNT[0] = ((RecyclerView) item).getAdapter().getItemCount();
                return true;
            }
            @Override
            public void describeTo(Description description) {}
        };
        onView(allOf(withId(RecyclerViewId),isDisplayed())).check(matches(matcher));
        return COUNT[0];
    }
    

    【讨论】:

      【解决方案6】:

      我使用下面的方法来获取 RecyclerView 的计数

      public static int getCountFromRecyclerView(@IdRes int RecyclerViewId) {
      int COUNT = 0;
              Matcher matcher = new TypeSafeMatcher<View>() {
                  @Override
                  protected boolean matchesSafely(View item) {
                      COUNT = ((RecyclerView) item).getAdapter().getItemCount();
                      return true;
                  }
                  @Override
                  public void describeTo(Description description) {
                  }
              };
              onView(allOf(withId(RecyclerViewId),isDisplayed())).check(matches(matcher));
              int result = COUNT;
                  COUNT = 0;
              return result;
          }
      

      用法-

      int itemsCount = getCountFromRecyclerView(R.id.RecyclerViewId);
      

      然后执行断言检查 itemsCount 是否符合预期

      【讨论】:

        【解决方案7】:

        您可以创建自定义BoundedMatcher:

        object RecyclerViewMatchers {
            @JvmStatic
            fun hasItemCount(itemCount: Int): Matcher<View> {
                return object : BoundedMatcher<View, RecyclerView>(
                    RecyclerView::class.java) {
        
                    override fun describeTo(description: Description) {
                        description.appendText("has $itemCount items")
                    }
        
                    override fun matchesSafely(view: RecyclerView): Boolean {
                        return view.adapter.itemCount == itemCount
                    }
                }
            }
        }
        

        然后像这样使用它:

        onView(withId(R.id.recycler_view)).check(matches((hasItemCount(5))))
        

        【讨论】:

          【解决方案8】:

          使用 ActivityScenarioRule 计数

          @get: Rule
          val activityScenarioRule = ActivityScenarioRule(ShowListActivity::class.java)
          @Test
          fun testItemCount(){
          activityScenarioRule.scenario.onActivity { activityScenarioRule ->
              val recyclerView = activityScenarioRule.findViewById<RecyclerView(R.id.movieListRecyclerView)
              val itemCount = recyclerView.adapter?.itemCount?:0
              ....
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-04-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多