私のテストでは、1つのアクションの後、表示される可能性のある2つのビューがあり、両方とも正しいです。ビューの1つが表示されているかどうかを確認するにはどうすればよいですか。確認できる単一のビューについては、Displayed()です。ただし、代わりに他のビューが表示されている場合は失敗します。これらの2つのビューのいずれかが表示される場合、テストに合格したいです。
onMyButton.perform(click());
onMyPageOne.check(matches(isDisplayed())); //view 1
or
onMyPageTwo.check(matches(isDisplayed())); //view 2
その後、MyButtonをクリックすると、ビューのいずれか(1または2)が表示されますが、両方は表示されません。どれが表示されるかは固定されていません。それらのいずれかが表示されているかどうかを確認するにはどうすればよいですか?
次のように、エスプレッソによって発生した例外をキャッチすることができます。
ビューが階層内にあるかどうかをテストする場合:
try {
onView(withText("Button")).perform(click());
// View is in hierarchy
} catch (NoMatchingViewException e) {
// View is not in hierarchy
}
ビューが階層内でnotの場合、この例外がスローされます。
ビューが階層内にある場合もありますが、表示されるかどうかをテストする必要があるため、次のようなアサーションには別の例外があります。
try {
onView(withText("Button")).check(matches(isDisplayed()));
// View is displayed
} catch (AssertionFailedError e) {
// View not displayed
}
ここで、カバーしようとしている可能性のある2つのケースがあります。 1つは、ビュー"ユーザーに対して画面に表示される"であるかどうかを確認する場合です。この場合、isDisplayed()
を使用します
onView(matcher).check(matches(isDisplayed()));
または否定
onView(matcher).check(matches(not(isDisplayed())));
もう1つのケースは、ビューが表示されているが、必ずしも画面(スクロールビューのアイテム)に表示されているわけではないかどうかを確認している場合です。これにはwithEffectiveVisibility(Visibility)
を使用できます
onView(matcher).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
Matchers.anyOf を使用して、2つのビューのいずれかが表示されているかどうかを確認できます。
onView(
anyOf(withId(R.id.view_1), withId(R.id.view_2))
).check(matches(isDisplayed()));
私はエスプレッソを少し研究しましたが、これは@ エスプレッソサンプル でした。
検索テキスト「ビューが表示されないことを確認する」。 「ビューがまだ階層の一部である場合、上記のアプローチは機能します。」したがって、コードは機能するはずですが、ViewAssertions
も使用する必要があります。コードを使用して、おそらくこれを行います:
if (ViewAssertions.doesNotExist()) == null) {
return;
}
onMyPageOne.check(matches(isDisplayed()));
別の手法は、UIの存在を確認することです。 「ビューが存在しないことを確認する」というテキストを検索します。あなたのコードを使用して、私の最良の提案は次のとおりです。
onMyPageOne.check(doesNotExist());
注:これはdoesNotExist
メソッドを呼び出します。
サンプルコードは次のとおりです。onView(withId(R.id.bottom_left)).check(doesNotExist());
ビューの可視性ステータスを確認したい人向け。ここに私が使用するいくつかのユーティリティ関数があります。
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()
ビューがvisible
、gone
、またはinvisible
であるかどうかを確認できるユーティリティクラス:
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
、isAttachedToWindow
、alpha
をチェックします。
class 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
}
}
}
問題は、すべてのassertoin()
およびcheck()
メソッドが失敗した場合にテストフローを停止するAssertion
を返すことです。
ビューまたはボタンのようなサブクラスをチェックする簡単な方法の1つは、メソッドgetVisibility from Viewクラスを使用することです。 GUIの世界では、可視性属性が明確に定義されていないことに注意する必要があります。ビューは可視であると見なされる場合がありますが、別のビューと重なる場合があります。たとえば、非表示にする場合があります。
別の方法ですが、より正確です(試したことはありません)。ビューの長方形の境界を確認することです。それほど単純ではありません。
これで十分ですか?コードを投稿しなかったため、具体的な例を挙げることはできません。
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()));
}