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

Cha*_*ham 38 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
 }
Run Code Online (Sandbox Code Playgroud)

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

 if (UiAutomator.getbyId(SomeId).exists()){
      .....
   }
Run Code Online (Sandbox Code Playgroud)

Val*_*rov 79

测试中的条件逻辑是不合需要的.考虑到这一点,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
    }
Run Code Online (Sandbox Code Playgroud)

  • @ValeraZakharov*unit*测试中的条件逻辑可能是不合需要的,但UI自动化框架应该执行功能测试,而不是"UI单元测试".通常需要条件逻辑才能进入已知的UI启动状态,尤其是对于应用程序的视图和逻辑深入的测试.从UI角度看,应用程序不是线性的.每次要测试步骤200,201和202时,您不希望从步骤1开始.用户是否每次想要选择其他菜单并查看显示内容时是否重新安装应用程序?没有. (11认同)
  • 这里的点是`isDisplayed`只有在视图在屏幕内时才有效.在补间动画上,视图应该存在,但它可能在屏幕之外. (6认同)
  • 在仪表化应用程序的过程中切换活动时没有什么特别的事情要做.如果控制流离开您的应用程序,则无法与UI交互(这是Android检测的限制). (4认同)
  • 开发人员编写的UI测试可以而且应该是确定性的(就像单元测试一样).去年,我在演讲中概述了如何在Android上实现这一目标:https://slideslive.com/38897360/a-practical-guide-to-writing-solid-ui-tests-on-android-en.有一个地方可以进行一些end2end UI测试(你可能无法完全控制环境),但这并不是Espresso尝试解决的问题(因此,API并不容易) . (2认同)
  • 像这样束缚开发人员的手,只是库设计不好。您不知道我的用例。库应该使编写代码变得容易,它们永远不应阻止开发人员编写他想编写的代码。另外,我知道的几乎所有Espresso用途都是用于用户交互测试。没有人将其用于单元测试。我什至不认为没有用户交互性测试的图形组件的单元测试在远程上是有用的-看着组件的人远胜于自动化测试。 (2认同)

小智 9

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

https://github.com/marcosdiez/espresso_clone

if(onView(withText("click OK to Continue")).exists()){ 
    doSomething(); 
} else { 
   doSomethingElse(); 
}
Run Code Online (Sandbox Code Playgroud)

我希望它对你有用.

  • Espresso 2.0,2.1有exists()方法吗?我没看到com.android.support.test.espresso中的这个mehod:espresso-core:2.1' (28认同)
  • @ShivarajPatil不,这是浓缩咖啡的克隆.请参阅答案中的链接. (5认同)

小智 9

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

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


TWi*_*Rob 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

public static ViewAssertion exists() {
    return matches(anything());
}
Run Code Online (Sandbox Code Playgroud)

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


Dav*_*vid 6

为什么没有人提到:

onView(withId(R.id.some_view_id)).check(matches(not(doesNotExist())))
Run Code Online (Sandbox Code Playgroud)

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


tro*_*per 5

基于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];
}
Run Code Online (Sandbox Code Playgroud)

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