Espresso:如果视图存在则返回布尔值

时间:2013-12-27 20:07:35

标签: java android android-testing android-espresso

我正在尝试检查Espresso是否显示视图。这是一些伪代码,用于显示我正在尝试的内容:

if (!Espresso.onView(withId(R.id.someID)).check(doesNotExist()){
   // then do something
 } else {
   // do nothing, or what have you
 }

但我的问题是.check(doesNotExist())没有返回布尔值。这只是一个断言。使用UiAutomator,我能够做到这样的事情:

 if (UiAutomator.getbyId(SomeId).exists()){
      .....
   }

8 个答案:

答案 0 :(得分:65)

测试中的条件逻辑是undesirable。考虑到这一点,Espresso的API旨在引导测试作者远离它(通过明确的测试操作和断言)。

话虽如此,你仍然可以通过实现自己的ViewAction并将isDisplayed检查(在perform方法中)​​捕获到AtomicBoolean来实现上述目的。

另一个不太优雅的选项 - 捕获失败检查引发的异常:

    try {
        onView(withText("my button")).check(matches(isDisplayed()));
        //view is displayed logic
    } catch (NoMatchingViewException e) {
        //view not displayed logic
    }

答案 1 :(得分:9)

您也可以使用以下代码进行检查。如果显示视图,它将单击否则将传递。

onView(withText("OK")).withFailureHandler(new FailureHandler() {
        @Override
        public void handle(Throwable error, Matcher<View> viewMatcher){
        }
    }).check(matches(isDisplayed())).perform(customClick());

答案 2 :(得分:9)

我认为模仿UIAutomator你可以这样做:
虽然,我建议重新考虑你没有条件的方法。

ViewInteraction view = onView(withBlah(...)); // supports .inRoot(...) as well
if (exists(view)) {
     view.perform(...);
}

@CheckResult
public static boolean exists(ViewInteraction interaction) {
    try {
        interaction.perform(new ViewAction() {
            @Override public Matcher<View> getConstraints() {
                return any(View.class);
            }
            @Override public String getDescription() {
                return "check for existence";
            }
            @Override public void perform(UiController uiController, View view) {
                // no op, if this is run, then the execution will continue after .perform(...)
            }
        });
        return true;
    } catch (AmbiguousViewMatcherException ex) {
        // if there's any interaction later with the same matcher, that'll fail anyway
        return true; // we found more than one
    } catch (NoMatchingViewException ex) {
        return false;
    } catch (NoMatchingRootException ex) {
        // optional depending on what you think "exists" means
        return false;
    }
}

没有分支的exists也可以非常简单地实现:

onView(withBlah()).check(exists()); // the opposite of doesNotExist()

public static ViewAssertion exists() {
    return matches(anything());
}

虽然大部分时间都值得检查matches(isDisplayed())

答案 3 :(得分:8)

我们需要这个功能,最后我在下面实现了它:

https://github.com/marcosdiez/espresso_clone

if(onView(withText("click OK to Continue")).exists()){ 
    doSomething(); 
} else { 
   doSomethingElse(); 
}

我希望它对你有用。

答案 4 :(得分:4)

根据Dhiren Mudgil的回答,我最后编写了以下方法:

public static boolean viewIsDisplayed(int viewId)
{
    final boolean[] isDisplayed = {true};
    onView(withId(viewId)).withFailureHandler(new FailureHandler()
    {
        @Override
        public void handle(Throwable error, Matcher<View> viewMatcher)
        {
            isDisplayed[0] = false;
        }
    }).check(matches(isDisplayed()));
    return isDisplayed[0];
}

我正在使用它来帮助确定当前显示ViewFlipper中的哪个View。

答案 5 :(得分:1)

自从这个问题出现以来已经有一段时间了,但是由于它是Google在寻找确保视图存在的方式时最受关注的问题之一,因此我想在Espresso中对其进行任何操作之前,先分享一下我最基本的处理方式。

1:首先将扩展名写入ViewInteraction

fun ViewInteraction.exists(): Boolean {
val viewExists = AtomicReference<Boolean>()

this.perform(object : ViewAction {
    override fun perform(uiController: UiController?, view: View?) {
        viewExists.set(view != null)
    }

    override fun getConstraints(): Matcher<View>? {
        return Matchers.allOf(ViewMatchers.withEffectiveVisibility(
                ViewMatchers.Visibility.VISIBLE),
                ViewMatchers.isAssignableFrom(View::class.java))
    }

    override fun getDescription(): String {
        return "check if view exists"
    }
})
return viewExists.get()

}

2:在基类中创建一个简单的帮助方法(将在所有测试类中使用):

fun viewExists(id: Int): Boolean {
    return try {
        onView(withId(id)).exists()
    } catch (e: RuntimeException) {
        false
    }
}

使用此方法,您可以从true获取falseonView(withId(id)).exists(),也可以安全地捕获RuntimeException并返回false

通常,对.exists()进行简单检查就足够了,但是在某些情况下,例如,当您删除ListView项目直到剩下non时->删除最后一个项目时,ListView可能不再存在,然后在尝试检查异常是否存在时抛出异常。

3:通过上述实现,可以安全地检查是否存在任何视图,因为RuntimeException在幕后得到了很好的处理:

if(viewExists(R.id.something)) {
    //do something
}
//do something else

答案 6 :(得分:0)

我认为Espresso希望您做的是改变使用doesNotExist()的逻辑

例如,我有

        onView(snackBarMatcher).check(doesNotExist())

        onView(withId(R.id.button)).perform(click())
        onView(snackBarMatcher).check(matches(isDisplayed()))


答案 7 :(得分:0)

为什么没人提到:

onView(withId(R.id.some_view_id)).check(matches(not(doesNotExist())))

只需在dosNotExist之前添加not。但是,如果您经常使用此逻辑,则最好使用自定义匹配器。