Espresso - 如何检查是否显示其中一个视图

时间:2015-03-25 08:16:57

标签: java listview android-testing android-espresso

在我的测试中,在一次操作之后,有两种可能的视图可以出现,并且它们都是正确的。如何检查是否显示其中一个视图。对于我可以检查的单个视图是Displayed()。但如果其他视图可见则会失败。如果显示这两个视图中的任何一个,我想通过测试。

onMyButton.perform(click());

onMyPageOne.check(matches(isDisplayed())); //view 1
or
onMyPageTwo.check(matches(isDisplayed())); //view 2

之后,执行点击MyButton,预计会出现任何一个视图(1或2),但不会同时出现。不确定哪一个会被显示。 如何检查是否显示其中任何一个?

10 个答案:

答案 0 :(得分:45)

可以像以下一样抓住Espresso提出的例外情况:

如果要测试视图是否在层次结构中:

try {
    onView(withText("Button")).perform(click());
    // View is in hierarchy

} catch (NoMatchingViewException e) {
    // View is not in hierarchy
}

如果层次结构中的视图不是,则会抛出此异常。

有时视图可以在层次结构中,但我们需要测试它是否显示,因此断言还有另一个例外,如:

try {
    onView(withText("Button")).check(matches(isDisplayed()));
    // View is displayed
} catch (AssertionFailedError e) {
    // View not displayed
}

答案 1 :(得分:30)

这里有两种情况你可以尝试覆盖。第一种是,如果您正在检查视图"是否在屏幕上显示给用户" ,在这种情况下您将使用isDisplayed()

onView(matcher).check(matches(isDisplayed()));

或否定

onView(matcher).check(matches(not(isDisplayed())));

另一种情况是,如果您正在检查视图是否可见但不一定显示在屏幕上(即滚动视图中的项目)。为此,您可以使用withEffectiveVisibility(Visibility)

onView(matcher).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));

答案 2 :(得分:20)

您可以使用Matchers.anyOf检查是否显示了两个视图中的任何一个:

onView(
   anyOf(withId(R.id.view_1), withId(R.id.view_2)) 
).check(matches(isDisplayed()));

答案 3 :(得分:8)

我研究了Espresso,我找到了这个@ Espresso Samples

  1. 搜索文本“断言未显示视图”。它说:“如果视图仍然是层次结构的一部分,则上述方法有效。”所以我认为你的代码应该可行,但你也需要使用ViewAssertions。使用您的代码,也许这样做:

    if (ViewAssertions.doesNotExist()) == null) {
       return;
    }
    onMyPageOne.check(matches(isDisplayed()));
    
  2. 另一种技术是检查UI是否存在。搜索文本“断言视图不存在”。 使用您的代码,我最好的建议是:

    onMyPageOne.check(doesNotExist());

  3. 注意:这会调用doesNotExist方法。

    他们的示例代码为:onView(withId(R.id.bottom_left)).check(doesNotExist());

答案 4 :(得分:6)

实用程序类,可以检查视图是goneinvisible还是public class ExtraAssertions { public static ViewAssertion isVisible() { return new ViewAssertion() { public void check(View view, NoMatchingViewException noView) { assertThat(view, new VisibilityMatcher(View.VISIBLE)); } }; } public static ViewAssertion isGone() { return new ViewAssertion() { public void check(View view, NoMatchingViewException noView) { assertThat(view, new VisibilityMatcher(View.GONE)); } }; } public static ViewAssertion isInvisible() { return new ViewAssertion() { public void check(View view, NoMatchingViewException noView) { assertThat(view, new VisibilityMatcher(View.INVISIBLE)); } }; } private static class VisibilityMatcher extends BaseMatcher<View> { private int visibility; public VisibilityMatcher(int visibility) { this.visibility = visibility; } @Override public void describeTo(Description description) { String visibilityName; if (visibility == View.GONE) visibilityName = "GONE"; else if (visibility == View.VISIBLE) visibilityName = "VISIBLE"; else visibilityName = "INVISIBLE"; description.appendText("View visibility must has equals " + visibilityName); } @Override public boolean matches(Object o) { if (o == null) { if (visibility == View.GONE || visibility == View.INVISIBLE) return true; else if (visibility == View.VISIBLE) return false; } if (!(o instanceof View)) throw new IllegalArgumentException("Object must be instance of View. Object is instance of " + o); return ((View) o).getVisibility() == visibility; } } }

onView(withId(R.id.text_message)).check(isVisible());

用法可能如下所示:

visibility

另一个视图断言可以帮助检查视图及其父项的额外可见性属性:它检查isAttachedToWindowalphaclass IsVisible : ViewAssertion { override fun check(view: View, noViewFoundException: NoMatchingViewException?) { ViewMatchers.assertThat( "View is not visible. " + "visibility: ${view.visibility}, " + "isAttachedToWindow: ${view.isAttachedToWindow}, " + "alpha: ${view.alpha}", true, `is`(isViewTreeVisible(view))) } private fun isViewTreeVisible(view: View?): Boolean { return if (view != null) { val viewVisible = view.isAttachedToWindow && view.visibility == View.VISIBLE && view.alpha == 1.0f if (view.parent !is View) viewVisible else viewVisible && isViewTreeVisible(view.parent as View) } else { true } } }

alter table dim_known_hosts drop if exists PARTITION (dimensional_partition_folder<'2016_01_04_00_30');

答案 5 :(得分:3)

问题是所有assertoin()check()方法都会返回Assertion,如果失败则会停止测试流程。

答案 6 :(得分:3)

对于那些希望查看视图可见性状态的对象;这是我使用的一些实用程序功能。

fun ViewInteraction.isGone() = getViewAssertion(ViewMatchers.Visibility.GONE)

fun ViewInteraction.isVisible() = getViewAssertion(ViewMatchers.Visibility.VISIBLE)

fun ViewInteraction.isInvisible() = getViewAssertion(ViewMatchers.Visibility.INVISIBLE)

private fun getViewAssertion(visibility: ViewMatchers.Visibility): ViewAssertion? {
    return ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(visibility))
}

并且可以如下使用

onView(withId(R.id.progressBar)).isVisible()
onView(withId(R.id.progressBar)).isGone()

答案 7 :(得分:1)

检查View或其子类(如Button)的一种简单方法是使用方法 来自查看类的 getVisibility 。我必须提醒一下,在GUI世界中没有明确定义可见性属性。视图可能被认为是可见的,但可能与另一个视图重叠,例如,使其隐藏。

另一种方法,但更准确(我还没试过)是检查视图的矩形边界。不那么简单。

这是否足够清楚?因为你没有发布代码,所以不能给你具体的例子。

答案 8 :(得分:0)

final AtomicBoolean view1Displayed = new AtomicBoolean(true);
Espresso.onView(ViewMatchers.withId(viewId1)).inRoot(RootMatchers.withDecorView(Matchers.is(intentsTestRule.getActivity().getWindow().getDecorView()))).withFailureHandler(new FailureHandler() {
        @Override
        public void handle(Throwable error, Matcher<View> viewMatcher) {
            view1Displayed.set(false);
        }
    }).check(ViewAssertions.matches(ViewMatchers.isDisplayed()));

if (view1Displayed.get()) {
        try {
            Espresso.onView(ViewMatchers.withId(viewId2)).inRoot(RootMatchers.withDecorView(Matchers.is(intentsTestRule.getActivity().getWindow().getDecorView()))).check(ViewAssertions.matches(Matchers.not(ViewMatchers.isDisplayed())));
        } catch (NoMatchingViewException ignore) {
        }
    } else {
        Espresso.onView(ViewMatchers.withId(viewId2)).inRoot(RootMatchers.withDecorView(Matchers.is(intentsTestRule.getActivity().getWindow().getDecorView()))).check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
    }

答案 9 :(得分:0)

当我遇到这种情况时,我通常会分为多个测试。一个测试设置要显示的视图1的条件,而另一项测试则设置要显示的视图2的条件。

但是,假设您无法真正控制条件。例如,如果它取决于随机数还是取决于第三方资源(例如服务器上的计算)怎么办?在那种情况下,我通常会解决模拟问题。这样,我可以控制条件,因此我确切地知道期望哪个视图。我使用依赖注入来设置每个测试所需的模拟。