检查是否显示了数组中视图的资源ID并单击它(Android-Espresso)

时间:2016-08-24 14:00:50

标签: android ui-automation android-espresso

我有以下情况。我们使用Gherkin语言通过Espresso推动我们的原生ui自动化。在我们的Gherkin系列中,我们有一行名为:

And I tap on button "Next"

其中“Next”是一个变量String我们传递给我们的胶水代码(我们使用的是Cucumber框架)。

碰巧,我们的应用程序有许多“下一步”按钮,具有不同的资源ID。最后我使用了带有变量的小黄瓜线:

And I tap on button "Next in screen 1"
And I tap on button "Next in screen 2"

现在我想在我的代码中只使用Gherkin变量“Next”。我得到一个Integer数组,其中包含来自所有Next按钮的所有资源id,但是当我想检查屏幕上显示哪个id时,我得到了NoMatchingViewException。

这是我目前的解决方案:

    final int[] uiElementIds = getArrayWithIdsFromUIElement("Next");

    int testId = 0;
    for(int id : uiElementIds) {
        try {
            onView(withId(id)).check(matches(isDisplayed()));
            testId = id;
            break;
        } catch(NoMatchingViewException ex) {
            // do nothing
        }
    }

    final int uiElementId = testId;
    onView(withId(uiElementId)).withFailureHandler(new FailureHandler() {
            @Override
            public void handle(Throwable error, Matcher<View> viewMatcher) {
                onView(withId(uiElementId)).perform(scrollTo(), click());
            }
        }).perform(click());

正如你所看到的,我只是捕获抛出的NoMatchingViewException,并且在找到正确的id并突破for循环之前不做任何事情。

我的问题是:

是否有更好的方法可以用来循环查看显示哪个ID,如果是,点击它?

在我看来,我提出了这个想法,但它没有集成在Espresso中:

for(int id : uiElementIds) {
 if(onView(withId(id)).exist()) {
    performClick();
 }
}

1 个答案:

答案 0 :(得分:1)

根据你的问题

  

我的问题是:

     

我们可以使用更好的方法来循环查看显示的ID,如果是,请点击它吗?

     

在我看来,我提出了这个想法,但它没有被整合   浓咖啡:

for(int id : uiElementIds) {
 if(onView(withId(id)).exist()) {
    performClick();
 }
}

这是我原来的Espresso框架Activity测试:

@RunWith(AndroidJUnit4.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class DetailsActivityTest {

    @Rule
    public ActivityTestRule<MainActivity_> mRule = new ActivityTestRule<>(MainActivity_.class);

    //TODO: Write tests to check if views are visible
    private final int[] allDetailsActivityViewsIdis = {
            R.id.dItem,
            R.id.dDayAndDate,
            R.id.dDay,
            R.id.dDate,
            R.id.dCity,
            R.id.dTempAndIcon,
            R.id.dTemperature,
            R.id.dHighTemp,
            R.id.dLowTemp,
            R.id.dDescriptionLayout,
            R.id.dDescription,
            R.id.dForecast,
            R.id.dHumidityLayout,
            R.id.dHumidityDesc,
            R.id.dHumidityVal,
            R.id.dPressureLayout,
            R.id.dPressureDesc,
            R.id.dPressureVal,
            R.id.dWindLayout,
            R.id.dWindDesc,
            R.id.dWindVal

    };

    private final int[] detailsActivityTextViewsIdis = {
            R.id.dDay,
            R.id.dDate,
            R.id.dHighTemp,
            R.id.dLowTemp,
            R.id.dDescription,
            R.id.dHumidityVal,
            R.id.dPressureVal,
            R.id.dWindVal,

    };

    private final int[] detailsActivityTextViewsDefaultValues = {
            R.string.day,
            R.string.date,
            R.string.high_temp,
            R.string.low_temp,
            R.string.description,
            R.string.humidity_val,
            R.string.pressure_val,
            R.string.wind_val,

    };

    @Before
    //TODO: Rewrite this code using espresso-intents
    public void checkIfAllDetailActivityViewsAreDisplayed() throws InterruptedException {
        for (int viewId : allDetailsActivityViewsIdis)
           onView(withId(viewId)).perform(click());

    }

    @Test
    public void checkIfDetailsActivityViewsHaveNoDefaultValue() throws InterruptedException {
        for (int viewId : detailsActivityTextViewsIdis)
            for (int valueId : detailsActivityTextViewsDefaultValues)
                onView(withId(viewId)).check(matches(not(withText(valueId))));

    }

}

如您所见,可以使用foreach使用Espresso,但exists()代替check(matches(...)使用值isDisplayedisDisplayedAtLeast或{{1} isCompletelyDisplayed }}

希望它能帮到你