Espresso

Espresso-Web ist ein Einstiegspunkt für die Arbeit mit Android WebView-UI-Komponenten. Espresso-Web verwendet Atoms der beliebten WebDriver API, um das Verhalten eines WebView zu untersuchen und zu steuern.

Wann sollte EspressoWeb verwendet werden?

Mit Espresso-Web können Sie Hybridanwendungen testen, insbesondere die Einbindung der nativen UI-Komponenten der App in die WebView-UI-Komponenten. Sie können die Espresso-Web API zusammen mit anderen Espresso APIs verwenden, um vollständig mit Webelementen in WebView-Objekten zu interagieren.

Wenn Sie nur das WebView selbst und nicht die Interaktionen zwischen der WebView und den nativen Komponenten in Ihrer App testen möchten, sollten Sie einen allgemeinen Webtest mit einem Framework wie WebDriver schreiben. Wenn Sie ein Webtest-Framework verwenden, benötigen Sie kein Android-Gerät oder eine Java Virtual Machine, wodurch Ihre Tests schneller und zuverlässiger ausgeführt werden. Dennoch bietet Espresso-Web die Möglichkeit, Ihre benutzerdefinierten WebDriver-Atome wiederzuverwenden. Dies bietet Ihnen ein hohes Maß an Flexibilität, insbesondere beim Schreiben von Tests, die sowohl für eigenständige Webanwendungen als auch für Anwendungen mit Android-UI ausgeführt werden sollen.

So funktionierts

Ähnlich wie bei der onData()-Methode von Espresso umfasst eine WebView-Interaktion mehrere Atoms. WebView-Interaktionen verwenden für ihre Arbeit eine Kombination aus der Programmiersprache Java und einer JavaScript-Bridge. Da es keine Möglichkeit gibt, Race-Bedingungen durch Offenlegung von Daten aus der JavaScript-Umgebung einzuführen, ist alles, was Espresso auf der Java-basierten Seite sieht, eine isolierte Kopie. Die Rückgabe von Daten von Web.WebInteraction-Objekten wird vollständig unterstützt, sodass Sie alle Daten überprüfen können, die von einer Anfrage zurückgegeben werden.

Was ist ein WebDriver-Atom?

Das WebDriver-Framework nutzt Atoms, um Webelemente programmatisch zu finden und zu bearbeiten. Atome werden von WebDriver verwendet, um Browsermanipulationen zu ermöglichen. Ein Atom ähnelt im Konzept einer ViewAction, einer eigenständigen Einheit, die eine Aktion auf der UI ausführt. Sie stellen Atome mit einer Liste definierter Methoden wie findElement() und getElement() bereit, um den Browser aus der Sicht des Nutzers zu steuern. Wenn Sie jedoch das WebDriver-Framework direkt verwenden, müssen Atoms ordnungsgemäß orchestriert werden. Dies erfordert eine ziemlich ausführliche Logik.

In Espresso wird dieser Boilerplate-Code von den Klassen Web und Web.WebInteraction umschlossen. So entsteht bei der Interaktion mit WebView-Objekten ein Espresso-ähnliches Gefühl. Im Kontext einer WebView werden also Atoms als Ersatz für den traditionellen Espresso ViewMatchers und ViewActions verwendet.

Die API sieht dann recht einfach aus:

Kotlin

onWebView()
    .withElement(Atom)
    .perform(Atom)
    .check(WebAssertion)

Java

onWebView()
    .withElement(Atom)
    .perform(Atom)
    .check(WebAssertion);

Weitere Informationen finden Sie in der Dokumentation zu Selenium zu Atoms.

WebView implementieren

Folgen Sie der Anleitung in den folgenden Abschnitten, um in den Tests Ihrer App mit WebView zu arbeiten.

Pakete

Führen Sie die folgenden Schritte aus, um Espresso-Web in Ihr Projekt aufzunehmen:

  1. Öffnen Sie die build.gradle-Datei Ihrer App. Dies ist normalerweise nicht die Datei build.gradle der obersten Ebene, sondern app/build.gradle.
  2. Fügen Sie innerhalb der Abhängigkeiten die folgende Zeile hinzu:

    Groovig

        androidTestImplementation 'androidx.test.espresso:espresso-web:3.4.0'
        

    Kotlin

        androidTestImplementation('androidx.test.espresso:espresso-web:3.4.0')
        
  3. Espresso-Web ist nur mit Espresso 2.2 oder höher und Version 0.3 oder höher der Testbibliothek kompatibel. Achten Sie daher darauf, diese Zeilen ebenfalls zu aktualisieren:

    Groovig

        androidTestImplementation 'androidx.test:runner:1.4.0'
        androidTestImplementation 'androidx.test:rules:1.4.0'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
        

    Kotlin

        androidTestImplementation('androidx.test:runner:1.4.0')
        androidTestImplementation('androidx.test:rules:1.4.0')
        androidTestImplementation('androidx.test.espresso:espresso-core:3.4.0')
        

Häufige API-Verwendung

Die onWebView()-Methode ist der Haupteinstiegspunkt für die Arbeit mit WebView unter Android mit Espresso. Sie verwenden diese Methode, um Espresso-Web-Tests wie die folgenden durchzuführen:

Kotlin

onWebView()
    .withElement(findElement(Locator.ID, "link_2")) // similar to onView(withId(...))
    .perform(webClick()) // Similar to perform(click())

    // Similar to check(matches(...))
    .check(webMatches(getCurrentUrl(), containsString("navigation_2.html")))

Java

onWebView()
    .withElement(findElement(Locator.ID, "link_2")) // similar to onView(withId(...))
    .perform(webClick()) // Similar to perform(click())

    // Similar to check(matches(...))
    .check(webMatches(getCurrentUrl(), containsString("navigation_2.html")));

In diesem Beispiel sucht Espresso-Web nach einem DOM-Element mit der ID "link_2" und klickt darauf. Das Tool überprüft dann, ob WebView eine GET-Anfrage mit dem String "navigation_2.html" sendet.

JavaScript-Unterstützung

Beim Ausführen der Tests führt das System alle WebView-Interaktionen mithilfe von JavaScript aus. Damit die JavaScript-Auswertung unterstützt werden kann, muss für das zu testende WebView JavaScript aktiviert sein.

Sie können die Aktivierung von JavaScript erzwingen, indem Sie forceJavascriptEnabled() als Aktion in Ihrer Testaktivität aufrufen, wie im folgenden Code-Snippet gezeigt.

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule val activityScenarioRule =
        activityScenarioRule<MyWebViewActivity>()

    @Test fun testWebViewInteraction() {
        onWebView().forceJavascriptEnabled()
    }
}

Häufige Webinteraktionen

Zu den häufigsten Interaktionen mit Web.WebInteraction-Objekten gehören:

  • withElement() verweist auf ein DOM-Element in WebView.

    Beispiel:

    Kotlin

    onWebView().withElement(findElement(Locator.ID, "teacher"))
    

    Java

    onWebView().withElement(findElement(Locator.ID, "teacher"));
    
  • withContextualElement() verweist auf ein beschränktes DOM-Element in WebView, relativ zu einem anderen DOM-Element. Sie müssen zuerst withElement() aufrufen, um das Web.WebInteraction-Referenzobjekt (DOM-Element) zu erstellen.

    Beispiel:

    Kotlin

    .withElement(findElement(Locator.ID, "teacher"))
        .withContextualElement(findElement(Locator.ID, "person_name"))
    

    Java

    .withElement(findElement(Locator.ID, "teacher"))
        .withContextualElement(findElement(Locator.ID, "person_name"));
    
  • check() wertet eine Bedingung aus und sorgt dafür, dass sie zu true aufgelöst wird.

    Beispiel:

    Kotlin

    onWebView()
        .withElement(findElement(Locator.ID, "teacher"))
        .withContextualElement(findElement(Locator.ID, "person_name"))
        .check(webMatches(getText(), containsString("Socrates")))
    

    Java

    onWebView()
        .withElement(findElement(Locator.ID, "teacher"))
        .withContextualElement(findElement(Locator.ID, "person_name"))
        .check(webMatches(getText(), containsString("Socrates")));
    
  • perform() führt eine Aktion in einem WebView aus, z. B. das Klicken auf ein Element.

    Beispiel:

    Kotlin

    onWebView()
        .withElement(findElement(Locator.ID, "teacher"))
        .perform(webClick())
    

    Java

    onWebView()
        .withElement(findElement(Locator.ID, "teacher"))
        .perform(webClick());
    
  • reset() setzt WebView auf seinen Ausgangszustand zurück. Dies ist erforderlich, wenn eine vorherige Aktion, z. B. ein Klick, eine Navigationsänderung bewirkt, die ElementReference- und WindowReference-Objekte nicht mehr zugänglich macht.

    Hinweis:Obwohl die Verwendung von reset() bei Assertions für mehrseitige Workflows wie Formulareinreichungen nützlich ist, sollten Ihre Tests in der Regel einen begrenzten Umfang haben und sich auf eine einzelne Seite konzentrieren.

    Beispiel:

    Kotlin

    onWebView()
        .withElement(...)
        .perform(...)
        .reset()
    

    Java

    onWebView()
        .withElement(...)
        .perform(...)
        .reset();
    

Beispiel

Im folgenden Beispiel wird getestet, ob nach der Eingabe von Text in ein WebView und der Auswahl der Schaltfläche Senden der gleiche Text in einem anderen Element in derselben WebView angezeigt wird:

Kotlin

const val MACCHIATO = "Macchiato"

@RunWith(AndroidJUnit4::class)
class MyEspressoWebTestSuite {

    @Test fun typeTextInInput_clickButton_SubmitsForm() {
        // Create an intent that displays a web form.
        val webFormIntent = Intent()
        // ...

        // Lazily launch the Activity with a custom start Intent per test.
        ActivityScenario.launchActivity(webFormIntent)

        // Selects the WebView in your layout. If you have multiple WebView
        // objects, you can also use a matcher to select a given WebView,
        // onWebView(withId(R.id.web_view)).
        onWebView()
            // Find the input element by ID.
            .withElement(findElement(Locator.ID, "text_input"))

            // Clear previous input and enter new text into the input element.
            .perform(clearElement())
            .perform(DriverAtoms.webKeys(MACCHIATO))

            // Find the "Submit" button and simulate a click using JavaScript.
            .withElement(findElement(Locator.ID, "submitBtn"))
            .perform(webClick())

            // Find the response element by ID, and verify that it contains the
            // entered text.
            .withElement(findElement(Locator.ID, "response"))
            .check(webMatches(getText(), containsString(MACCHIATO)))
    }
}

Java

public static final String MACCHIATO = "Macchiato";

@Test
public void typeTextInInput_clickButton_SubmitsForm() {
    // Create an intent that displays a web form.
    Intent webFormIntent = new Intent();
    // ...

    // Lazily launch the Activity with a custom start Intent per test.
    ActivityScenario.launchActivity(webFormIntent);

    // Selects the WebView in your layout. If you have multiple WebView objects,
    // you can also use a matcher to select a given WebView,
    // onWebView(withId(R.id.web_view)).
    onWebView()
        // Find the input element by ID.
        .withElement(findElement(Locator.ID, "text_input"))

        // Clear previous input and enter new text into the input element.
        .perform(clearElement())
        .perform(DriverAtoms.webKeys(MACCHIATO))

        // Find the "Submit" button and simulate a click using JavaScript.
        .withElement(findElement(Locator.ID, "submitBtn"))
        .perform(webClick())

        // Find the response element by ID, and verify that it contains the
        // entered text.
        .withElement(findElement(Locator.ID, "response"))
        .check(webMatches(getText(), containsString(MACCHIATO)));
}

Weitere Informationen

Weitere Informationen zur Verwendung von Espresso-Web in Android-Tests finden Sie in den folgenden Ressourcen.

Produktproben

  • WebBasicSample: Verwenden Sie Espresso-Web, um mit WebView-Objekten zu interagieren.