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.
问自己以下问题:
- 此操作是否可由真实用户执行?如果是这样,他实际需要多少根手指?
- 这样的行动会产生什么结果?在您的情况下,每个单独的点击事件都会更新 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 将在适配器中找到(在测试执行期间)并单击它。
我有一个 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.
问自己以下问题:
- 此操作是否可由真实用户执行?如果是这样,他实际需要多少根手指?
- 这样的行动会产生什么结果?在您的情况下,每个单独的点击事件都会更新 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 将在适配器中找到(在测试执行期间)并单击它。