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()){
.....
}
_
テストの条件論理は 望ましくない です。そのことを念頭に置いて、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
}
拡張機能付きのKotlinバージョン:
fun ViewInteraction.isDisplayed(): Boolean {
try {
check(matches(ViewMatchers.isDisplayed()))
return true
} catch (e: NoMatchingViewException) {
return false
}
}
if(onView(withText("my button")).isDisplayed()) {
//view is displayed logic
} else {
//view not displayed logic
}
以下のコードでも確認します。ビューが表示されている場合は、他のビューをクリックしてパスします。
onView(withText("OK")).withFailureHandler(new FailureHandler() {
@Override
public void handle(Throwable error, Matcher<View> viewMatcher){
}
}).check(matches(isDisplayed())).perform(customClick());
その機能が必要なので、私はそれを以下に実装することになりました。
https://github.com/marcosdiez/espresso_clone
if(onView(withText("click OK to Continue")).exists()){
doSomething();
} else {
doSomethingElse();
}
皆さんのお役に立てば幸いです。
私はあなたがこれを行うことができる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())
をチェックする価値はありますが。
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のどのビューが現在表示されているかを判断します。
この問題が発表されてからしばらく経ちましたが、ビューが存在することを確認する方法を検索する際にGoogleのトップヒットの1つであるため、エスプレッソでアクションを実行する前に、非常に基本的なことを共有したいと思いますこれを処理する方法。
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
}
}
_
これにより、onView(withId(id)).exists()
からtrue
またはfalse
を取得するか、RuntimeExceptionを安全にキャッチしてfalse
を返します。
通常、.exists()
に対する簡単なチェックで十分ですが、場合によっては、リストビューアイテムを削除し、最後のアイテムが削除されるまで、リストビューが存在しない場合があります。存在するかどうかを確認しようとすると、例外がスローされます。
3:上記の実装では、RuntimeException
が舞台裏で適切に処理されるため、ビューが存在するかどうかを確認しても安全です。
_if(viewExists(R.id.something)) {
//do something
}
//do something else
_
エスプレッソがあなたに望んでいるのは、doesNotExist()
を使用するようにロジックを変更することだと思います
私は例えば
onView(snackBarMatcher).check(doesNotExist())
onView(withId(R.id.button)).perform(click())
onView(snackBarMatcher).check(matches(isDisplayed()))