Espresso onData 执行点击多个项目

Espresso onData perform click on multiple items

我有一个 Gridview,其适配器基于我的 MineSweeper 游戏的 Tile 类型的 pojo 列表,我正在做一些单元测试,我想做的就是单击所有没有地雷的 gridview 项目并长按所有确实有项目

的项目

我试过以下方法:

onData(allOf(is(instanceOf(Tile.class)),isMineMatcher(true)))
            .inAdapterView(withId(R.id.f_minefield_gridview))
            .perform(longClick());

onData(allOf(is(instanceOf(Tile.class)),isMineMatcher(false)))
            .inAdapterView(withId(R.id.f_minefield_gridview))
            .perform(click());

使用我的自定义匹配器:

public static Matcher<Tile> isMineMatcher(final boolean flag){
    return new TypeSafeMatcher<Tile>() {
        @Override
        public boolean matchesSafely(Tile tile) {
            return tile.isMine() == flag;
        }

        @Override
        public void describeTo(Description description) {
            description.appendText("expected "+ flag);
        }
    };
}

但这会出现以下错误:

android.support.test.espresso.PerformException: Error performing 'load adapter data' on view 'with id: com.kaissersoft.minesweepergame:id/f_minefield_gridview'.
...
Caused by: java.lang.RuntimeException: Multiple data elements matched:

问题是如何使用 espresso 对多个项目执行操作?

简单的回答:你不知道。

用例首先被误导了。 Automating UI Tests 的目的是

write your UI tests such that user actions are performed in an automated way.

问自己以下问题:

  1. 此操作是否可由真实用户执行?如果是这样,他实际需要多少根手指?
  2. 这样的行动会产生什么结果?在您的情况下,每个单独的点击事件都会更新 UI 并将该特定图块标记为已访问。您的代码是否实际处理同时点击更多图块?

Espresso 的行为仅处理一次在一个视图上执行操作

我认为解决该问题的方法是遍历 gridview 中的所有项目并对每个项目执行所需的操作。

尝试使用 atPosition() 一次指向一个位置并执行所需的操作。

onData(allOf(is(instanceOf(Tile.class)),isMineMatcher(true)))
        .inAdapterView(withId(R.id.f_minefield_gridview))
        .atPosition(1)
        .perform(longClick());

更新:

我发现您只需将 .atPosition(0) 添加到 onData 中,这样它就会在第一个匹配项上执行您的 action/check:

onData(allOf(is(instanceOf(Tile.class)),isMineMatcher(true)))
            .atPosition(0)
            .inAdapterView(withId(R.id.f_minefield_gridview))
            .perform(longClick());

旧答案:

我遇到了类似的问题。我通过只为第一场比赛返回真来解决它:

public static Matcher<Tile> isMineMatcher(final boolean flag){
    return new TypeSafeMatcher<Tile>() {
        boolean mFound;

        @Override
        public boolean matchesSafely(Tile tile) {
            // only match the first view :)
            if (mFound) return false;

            mFound = tile.isMine() == flag;
            return mFound;
        }

        @Override
        public void describeTo(Description description) {
            description.appendText("expected "+ flag);
        }
    };
}

你为什么不试试,因为它在 testDroid 中给出。它对我有用:

如果您的适配器中有其他对象:

public class Person {
   public long id;
   public String firstName;
   public String lastName;
   public String email;
}

您可以将其与 onData 一起使用:

onData(allOf(is(new BoundedMatcher<Object, Person>(Person.class) {
    @Override
    public void describeTo(Description description) {
    }
    @Override
    protected boolean matchesSafely(Person obj) {
        return obj.id = 12345L;
    }
}))).inAdapterView(withId(<ADAPTER_ID>)).perform(click());

所以现在 id=12345 的 Person 将在适配器中找到(在测试执行期间)并单击它。