Espresso onData执行点击多个项目

时间:2015-04-23 03:52:22

标签: android gridview android-espresso

我有一个带有适配器的Gridview基于我的MineSweeper游戏的Tile类型的pojos列表,我做了一些单元测试,我想要做的就是点击所有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对多个项目执行操作?

3 个答案:

答案 0 :(得分:3)

简单回答:你没有。

用例首先是错误的。 Automating UI Tests的目的是

  

编写您的UI测试,以便以自动方式执行用户操作

问自己以下问题:

  1. 这个动作是否可以由真实用户执行?如果是这样,他实际需要多少手指?
  2. 这样的行动会有什么结果?在您的情况下,每个单独的单击事件都会更新UI并将该特定磁贴标记为已访问。您的代码是否实际上同时处理了更多瓷砖的点击?
  3. Espresso的行为只能一次处理在一个视图上执行操作

    我认为解决方案是迭代gridview中的所有项目并对每个项目执行所需的操作。

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

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

答案 1 :(得分:3)

更新

我发现您只需将.atPosition(0)添加到onData即可,以便对第一个匹配的项目执行操作/检查:

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

旧答案:

我有类似的问题。我通过在第一场比赛中返回true来解决它:

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

答案 2 :(得分:3)

为什么不尝试在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(在测试执行期间),它将被点击。

查看详细解释here