webentwicklung-frage-antwort-db.com.de

Espresso: Rückgabe boolean, wenn Ansicht vorhanden ist

Ich versuche zu prüfen, ob mit Espresso eine Ansicht angezeigt wird. Hier ist ein Pseudo-Code, um zu zeigen, was ich versuche:

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

Aber mein Problem ist, dass .check(doesNotExist()) nicht boolean zurückgibt. Es ist nur eine Behauptung. Mit UiAutomator konnte ich so etwas tun:

 if (UiAutomator.getbyId(SomeId).exists()){
      .....
   }
33
Chad Bingham

Bedingte Logik in Tests ist unerwünscht . Zu diesem Zweck wurde die API von Espresso entwickelt, um den Testautor davon abzuhalten (durch explizite Testaktionen und Assertions).

Sie können das obige dennoch erreichen, indem Sie Ihre eigene ViewAction implementieren und die isDisplayed-Prüfung (in der Perform-Methode) in einem AtomicBoolean erfassen.

Eine andere, weniger elegante Option - fangen Sie die Ausnahme ab, die durch eine fehlerhafte Überprüfung ausgelöst wird:

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

Um UIAutomator zu imitieren, können Sie Folgendes tun:
( Ich schlage jedoch vor, Ihre Vorgehensweise zu überdenken, um keine Bedingungen zu haben. )

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;
    }
}

Auch exists ohne Verzweigung kann sehr einfach implementiert werden:

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

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

Die meiste Zeit lohnt es sich ohnehin, nach matches(isDisplayed()) zu suchen.

9
TWiStErRob

Sie überprüfen auch den untenstehenden Code. Wenn die Ansicht angezeigt wird, klickt sie auf ein anderes Symbol, um weiterzugeben.

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

Wir brauchen diese Funktionalität und ich habe sie unten implementiert:

https://github.com/marcosdiez/espresso_clone

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

Ich hoffe es ist nützlich für dich.

8
user3411862

Basierend auf der Antwort von Dhiren Mudgil schrieb ich die folgende Methode: 

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];
}

Ich verwende dies, um zu ermitteln, welche Ansicht in einem ViewFlipper aktuell angezeigt wird.

4
trooper

Es wurde einige Zeit vergangen, seitdem dieses Problem festgestellt wurde. Da dies jedoch einer der Top-Treffer bei Google ist, wenn nach Wegen gesucht wird, um sicherzustellen, dass eine Ansicht vorhanden ist, bevor ich mit Espresso etwas dagegen unternehme, möchte ich Ihnen mein grundlegendes Element mitteilen wie man damit umgehen kann.

1: Beginnen Sie mit dem Schreiben einer Erweiterung in 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: Erstellen Sie eine einfache Hilfemethode in Ihrer Basisklasse (zur Verwendung in allen Testklassen):

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

Damit erhält man entweder true oder false von onView(withId(id)).exists() oder fängt die RuntimeException sicher ab und gibt false zurück.

Normalerweise reicht eine einfache Überprüfung von .exists() aus, aber in einigen Fällen, z. B. wenn Sie ListView-Elemente löschen, bis keine Elemente übrig sind -> Wenn das letzte Element gelöscht wird, ist die ListView möglicherweise nicht mehr vorhanden. Beim Versuch wird eine Ausnahme ausgelöst um zu prüfen, ob es existiert. 

3: Mit der obigen Implementierung können Sie sicher prüfen, ob eine Ansicht vorhanden ist, da der RuntimeException hinter der Szene gut gehandhabt wird:

if(viewExists(R.id.something)) {
    //do something
}
//do something else
1
Morten Løvborg

Ich denke, Espresso möchte, dass Sie Ihre Logik ändern, um doesNotExist() zu verwenden.

Ich habe zum Beispiel

        onView(snackBarMatcher).check(doesNotExist())

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


0
Duncan McGregor