问题
I have a Gridview with an adapter based on a list of pojos of type Tile for my MineSweeper game, Im doing some unit tests and all I want to do is Click on all gridview Items that dont have mines and longclick all items that does have items
I have tried with the following:
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());
with my custom matcher:
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);
}
};
}
But this presents the following error:
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:
The question is how to perform Actions on Multiple items with espresso?
回答1:
Why don't you try as it is given in testDroid. It worked for me:
If you have other objects in your adapter:
public class Person {
public long id;
public String firstName;
public String lastName;
public String email;
}
You can use this with 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());
So now Person with id=12345 will be found in the adapter (during test execution) and it will be clicked.
回答2:
Simple answer: you don't.
The use case is misguided in the first place. The purpose of Automating UI Tests is to
write your UI tests such that user actions are performed in an automated way.
Ask yourself the following questions:
- Is this action performable by a real user? If so, how many fingers would he actually need?
- What would be the outcome of such an action? In your case, each separate click event would update the UI and mark that specific tile as visited. Does your code actually handle clicking on more tiles at the same time?
Espresso's behavior only handles performing actions on one view at a time.
I think a solution to that would be to iterate through all items in the gridview and perform the desired action on each of them.
Try using atPosition() to point to exactly one location at a time and perform the desired action.
onData(allOf(is(instanceOf(Tile.class)),isMineMatcher(true)))
.inAdapterView(withId(R.id.f_minefield_gridview))
.atPosition(1)
.perform(longClick());
回答3:
Update:
I found out that you can simply add .atPosition(0)
to your onData
so it would perform your action/check on the first matched item:
onData(allOf(is(instanceOf(Tile.class)),isMineMatcher(true)))
.atPosition(0)
.inAdapterView(withId(R.id.f_minefield_gridview))
.perform(longClick());
Old Answer:
I had a similar issue. I solved it by only returning true for the first match:
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);
}
};
}
来源:https://stackoverflow.com/questions/29813336/espresso-ondata-perform-click-on-multiple-items