{"id":21051,"date":"2017-03-22T14:58:52","date_gmt":"2017-03-22T13:58:52","guid":{"rendered":"https:\/\/www.inovex.de\/blog\/?p=2840"},"modified":"2026-03-23T12:25:52","modified_gmt":"2026-03-23T11:25:52","slug":"android-ui-tests","status":"publish","type":"post","link":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/","title":{"rendered":"Android UI Tests mit dem Espresso Test Recorder und einem Mock Web Server"},"content":{"rendered":"<p>Obwohl sich das Espresso Framework schon seit l\u00e4ngerer Zeit zum Standard f\u00fcr UI-Tests unter Android etabliert hat, ist die H\u00fcrde noch immer recht hoch diese auch zu implementieren. Durch den Espresso Test Recorder, der mit <a href=\"https:\/\/android-developers.googleblog.com\/2016\/09\/android-studio-2-2.html\" target=\"_blank\" rel=\"noopener\">Android Studio 2.2<\/a> eingef\u00fchrt wurde, hat sich diese Schwierigkeit deutlich verringert. Wir wollen uns also damit besch\u00e4ftigen, wie wir relativ einfach UI-Tests generieren aber auch unabh\u00e4ngig von Remote-Servern machen k\u00f6nnen.<!--more--><\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_79_2 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\"><p class=\"ez-toc-title\" style=\"cursor:inherit\"><\/p>\n<\/div><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#Disclaimer\" >Disclaimer<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#Espresso-Test-Recorder\" >Espresso Test Recorder<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#MockWebServer\" >MockWebServer<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#ProductFlavor\" >ProductFlavor<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#Anpassung-des-Tests\" >Anpassung des Tests<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#Yet-another-Test\" >Yet another Test<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#Tipps\" >Tipps<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#scrollToNestedScrollView\" >scrollTo()\/NestedScrollView<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#CheckboxenRadio-Buttons\" >Checkboxen\/Radio Buttons<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#Firebase\" >Firebase<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#Verstaerkung-gesucht\" >Verst\u00e4rkung gesucht!<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"Disclaimer\"><\/span>Disclaimer<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Die Beispiel-Applikation soll zeigen, wie man relativ einfach mit\u00a0dem <a href=\"https:\/\/developer.android.com\/studio\/test\/espresso-test-recorder.html\" target=\"_blank\" rel=\"noopener\">Espresso Test Recorder<\/a> sowie einer Mock-API Testf\u00e4lle ausf\u00fchren kann.\u00a0Nat\u00fcrlich wird diese Beispiel-Applikation nicht alle Bereiche abdecken, mit denen wir uns tagt\u00e4glich im Android-Umfeld besch\u00e4ftigen. Grundlegende Dinge wie RxJava, Dagger sowie das MVP Pattern werden hier nicht ber\u00fccksichtigt, sollten aber in einer modernen Android App keinesfalls fehlen. Hierzu hat Kollege Daniel Ende 2016 bereits einen Vortrag auf dem GDG\u00a0DevFest in Karlsruhe <a href=\"http:\/\/dbaelz.de\/wp-content\/uploads\/2016\/11\/Moderne-Android-App.pdf\" target=\"_blank\" rel=\"noopener\">gehalten<\/a>.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Espresso-Test-Recorder\"><\/span>Espresso Test Recorder<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Wir haben also eine App, die einen einfachen Login gegen eine Remote-API ausf\u00fchren soll. Im Erfolgsfall werden wir eine neue Activity starten und auch hier Content \u00fcber eine API anzeigen. Sollte der Login fehlschlagen, so \u00f6ffnet sich ein\u00a0Dialog, in dem ein entsprechender Fehlertext angezeigt wird.<\/p>\n<p>Starten wir also den Espresso Test Recorder (<span class=\"lang:sh decode:true crayon-inline \">Run -&amp;gt; Record Espresso Test<\/span>) und klicken uns etwas durch den Login-Bereich, so begr\u00fc\u00dft uns beispielsweise dieser Stand.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-2841\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/1.png\" alt=\"\" width=\"600\" height=\"520\" \/><\/p>\n<p>Der Espresso Test Recorder f\u00fchrt also die App auf dem Emulator oder einem echten Ger\u00e4t aus und protokolliert Aktionen wie z.B Eingaben oder Klicks. Zus\u00e4tzlich hat man die M\u00f6glichkeit, anhand des aktuellen Bildschirminhalts Assertions auszuf\u00fchren, um den Zustand der App zu pr\u00fcfen.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-2842\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/2.png\" alt=\"\" width=\"599\" height=\"492\" \/><\/p>\n<p>Hat man sich bis zum gew\u00fcnschten Zustand der App durchnavigiert, etwaige Assertions hinzugef\u00fcgt und abgeschlossen, generiert Android Studio den passenden Code. Hierbei gilt es zu beachten, dass sich dieser generierte Code auf das verwendete Ger\u00e4t bezieht. Ist also z.B ein Bereich, der geklickt werden soll, auf einem kleineren Ger\u00e4t nicht sichtbar, schl\u00e4gt der Test auf diesem Ger\u00e4t fehl. Ein h\u00e4ufiger Fehlerfall \u2014 dazu sp\u00e4ter mehr.<\/p>\n<p>Wir werden am Ende 2 Testf\u00e4lle haben. Zum einen wollen wir pr\u00fcfen, ob ein fehlgeschlagener Login einen entsprechenden Dialog anzeigt, zum anderen, ob ein erfolgreicher Login uns zu unserer <span class=\"lang:sh decode:true crayon-inline \">MainActivity<\/span> f\u00fchrt, in der von der Mock-API bereitgestellte Daten korrekt angezeigt werden. Bevor man die Mock-API einf\u00fchrt, empfiehlt sich der Einfachheit halber, diese Tests mit einem echten Environment zu generieren und sie anschlie\u00dfend auf die Mock-API umzustellen.<\/p>\n<p><em>Lets have some code&#8230;<\/em><\/p>\n<pre class=\"lang:java decode:true\" title=\"Unser erster Test\">@Test\r\n\r\npublic void login_fail_should_display_error_dialog() throws Exception {\r\n\r\n    ViewInteraction emailEditText = onView(withId(R.id.edittext_email));\r\n\r\n    emailEditText.perform(scrollTo(), replaceText(\"as@asd.de\"), closeSoftKeyboard());\r\n\r\n    ViewInteraction pwEditText = onView(withId(R.id.edittext_password));\r\n\r\n    pwEditText.perform(scrollTo(), replaceText(\"12345\"), closeSoftKeyboard());\r\n\r\n    ViewInteraction signInButton = onView(withId(R.id.button_sign_in));\r\n\r\n    signInButton.perform(scrollTo(), click());\r\n\r\n    ViewInteraction dialogTitle = onView(allOf(withId(R.id.alertTitle), isDisplayed()));\r\n\r\n    dialogTitle.check(matches(withText(R.string.dialog_title_error)));\r\n\r\n    ViewInteraction dialogText = onView(allOf(withId(android.R.id.message), isDisplayed()));\r\n\r\n    dialogText.check(matches(withText(R.string.dialog_message_login_failed)));\r\n\r\n}<\/pre>\n<p>Wie man sieht, haben wir den vom TestRecorder generierten Code etwas abgespeckt und unn\u00f6tigen Code entfernt. Was wir nun haben, ist ein simpler Testfall, der auf unserer <span class=\"lang:sh decode:true crayon-inline \">LoginActivity<\/span> die Felder E-Mail und Passwort f\u00fcllt, anschlie\u00dfend auf den Sign In Button klickt und pr\u00fcft, ob ein Dialog mit entsprechenden Texten (Title &amp; Message) dargestellt wird.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"MockWebServer\"><\/span>MockWebServer<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Wir k\u00f6nnen diesen Test nun umstellen, um gegen die oben angek\u00fcndigte Mock-API zu testen. Hierf\u00fcr werden wir den von <a href=\"http:\/\/square.github.io\/okhttp\/\" target=\"_blank\" rel=\"noopener\">OkHttp<\/a> mitgelieferten MockWebServer nutzen. Mithilfe dieses MockWebServers k\u00f6nnen wir innerhalb der Tests vordefinierte Responses queuen und damit verschiedenes Verhalten der App testen.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"ProductFlavor\"><\/span>ProductFlavor<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Um zu definieren, welche Umgebung\/API-URL wir f\u00fcr die Tests nutzen wollen, gibt es verschiedene Ans\u00e4tze. Je nach Projekt-Setup k\u00f6nnen wir per Dagger ein entsprechendes Environment injecten, vor dem Test unsere Host URL entsprechend anpassen, oder einen neuen Gradle Build Flavor hinzuf\u00fcgen. Wir haben uns hier f\u00fcr die einfache Variante des Build Flavors entschieden:<\/p>\n<pre class=\"lang:default decode:true\" title=\"Product Flavor f\u00fcr unsere UI Tests\">productFlavors {\r\n\r\n    app {\r\n\r\n    }\r\n\r\n    ui_tests {\r\n\r\n        buildConfigField 'String', 'HOST', '\"http:\/\/127.0.0.1:43210\/api\/\"'\r\n\r\n    }\r\n\r\n}<\/pre>\n<p>Wir \u00fcberschreiben hierbei das buildConfigField, das wir in unserer defaultConfig definiert haben, mit einer lokalen URL auf Port 43210. Da wir in unserem Retrofit-Setup die Base URL per BuildConfig setzen, wird diese durch das Ausf\u00fchren der Tests mit dem ausgew\u00e4hlten Build Flavor entsprechend ersetzt.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Anpassung-des-Tests\"><\/span>Anpassung des Tests<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Nun passen wir unseren zuvor angelegten Test so an, dass die Mock-API entsprechend unseren Bed\u00fcrfnisse \u201egef\u00fcllt\u201c ist.<\/p>\n<pre class=\"lang:java decode:true \" title=\"Anpassung Test Mock-API\">private static MockWebServer server;\r\n\r\n@BeforeClass\r\n\r\npublic static void startMockServer() throws Exception {\r\n\r\n    server = new MockWebServer();\r\n\r\n    server.start(43210);\r\n\r\n}\r\n\r\n@AfterClass\r\n\r\npublic static void shutdownMockServer() throws Exception {\r\n\r\n    server.shutdown();\r\n\r\n}\r\n\r\n@Test\r\n\r\npublic void login_fail_should_display_error_dialog() throws Exception {\r\n\r\n    MockResponse loginResponse = new MockResponse().setResponseCode(403);\r\n\r\n    server.enqueue(loginResponse);\r\n\r\n    \/\/Der Rest des Codes bleibt unver\u00e4ndert..\r\n\r\n}<\/pre>\n<p>Wir legen also fest, dass zun\u00e4chst der MockWebServer mit entsprechendem Port (wie in unserem Flavor definiert) gestartet wird, bevor ein Test in dieser Testklasse ausgef\u00fchrt wird. Innerhalb des Tests queuen wir dann eine MockResponse mit dem <a href=\"https:\/\/en.wikipedia.org\/wiki\/HTTP_403\" target=\"_blank\" rel=\"noopener\">Response Code 403<\/a>.<\/p>\n<p>F\u00fchren wir unseren Test nun erneut aus, so verwendet Retrofit f\u00fcr alle API Requests unseren MockWebServer \u2013 den wir mit dem oben stehenden Code vorab gef\u00fcllt haben.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Yet-another-Test\"><\/span>Yet another Test<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Nun fehlt noch der versprochene zweite Test, der einen erfolgreichen Login ausf\u00fchren wird, um anschlie\u00dfend auf der MainActivity zu pr\u00fcfen, ob die korrekten Daten angezeigt werden.<\/p>\n<pre class=\"lang:java decode:true \" title=\"Zweiter Test\">@Test\r\n\r\npublic void login_success_should_lead_to_mainactivity_and_display_correct_string() throws Exception {\r\n\r\n    MockResponse loginResponse = new MockResponse().setResponseCode(200);\r\n\r\n    MockResponse someresponse = new MockResponse().setResponseCode(200)\r\n\r\n                .setBody(\"{\\\"isAndroidTestingFunny\\\": true}\");\r\n\r\n    server.enqueue(loginResponse);\r\n\r\n    server.enqueue(someresponse);\r\n\r\n    ViewInteraction emailEditTxt = onView(withId(R.id.edittext_email));\r\n\r\n    emailEditTxt.perform(scrollTo(), replaceText(\"as@asd.de\"), closeSoftKeyboard());\r\n\r\n    ViewInteraction pwEditText = onView(withId(R.id.edittext_password));\r\n\r\n    pwEditText.perform(scrollTo(), replaceText(\"12345\"), closeSoftKeyboard());\r\n\r\n    ViewInteraction signInButton = onView(withId(R.id.button_sign_in));\r\n\r\n    signInButton.perform(scrollTo(), click());\r\n\r\n    ViewInteraction textViewWithTextFromApi = onView(allOf(withId(R.id.textView), isDisplayed()));\r\n\r\n    textViewWithTextFromApi.check(matches(withText(\"Android testing is funny: true\")));\r\n\r\n}<\/pre>\n<p>Hier haben wir 2 Responses zu unserer Mock-API Queue hinzugef\u00fcgt: Die erste Response impliziert einen korrekten Login, w\u00e4hrend die zweite erfolgreiche Response einen Body hat, den wir hier im Code definiert haben. Bei gr\u00f6\u00dferen Responses bietet sich die M\u00f6glichkeit an, json-Dateien im Ordner <span class=\"lang:sh decode:true crayon-inline \">app\/src\/androidTest\/assets<\/span> abzulegen und auszulesen. (Siehe Beispielprojekt)<\/p>\n<p>Die hinzugef\u00fcgten Requests werden sequentiell hinzugef\u00fcgt, abgerufen und dadurch entfernt.<\/p>\n<p>Es sollte immer die genaue Anzahl der ben\u00f6tigten Requests hinzugef\u00fcgt werden, da bei zu wenigen Requests die App nicht wie erwartet funktionieren wird. Bei zu vielen hinzugef\u00fcgten Requests werden aller Voraussicht nach etwaige Folgetests scheitern, da diese auf einer Queue aufsetzen, die nicht korrekt f\u00fcr den jeweiligen Test vorbereitet ist.<\/p>\n<p>Indem wir unsere Tests auf eine lokale Mock-Umgebung umstellen ist gew\u00e4hrleistet, dass unsere Tests auch lokal ohne Zugang zum Remote Server funktionieren.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Tipps\"><\/span>Tipps<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"scrollToNestedScrollView\"><\/span>scrollTo()\/NestedScrollView<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Wie oben bereits erw\u00e4hnt, sind die generierten Tests immer auf das ausf\u00fchrende Ger\u00e4t zugeschnitten. Es ist also nicht un\u00fcblich, dass sie gerade auf Ger\u00e4ten mit verschiedenen Displaygr\u00f6\u00dfen zum Teil scheitern.<\/p>\n<p>Es empfiehlt sich also, auf verwendeten UI Elementen zus\u00e4tzlich zum Input\/Click noch ein <span class=\"lang:default decode:true crayon-inline \">scrollTo()<\/span>\u00a0 ausf\u00fchren zu lassen, um sicher zu stellen, dass wir unsere zu verwendende View auch sehen. <span class=\"lang:default decode:true crayon-inline \">scrollTo()<\/span>\u00a0kann auch verwendet werden, wenn wir wie in unserem Beispiel \u00fcberhaupt keine ScrollView verwenden.<\/p>\n<p><span class=\"lang:java decode:true crayon-inline\">button.perform(scrollTo(), click());<\/span><\/p>\n<p><span class=\"lang:default decode:true crayon-inline \">scrollTo()<\/span> hat leider\u00a0das Problem, dass es nicht korrekt bei der Verwendung von NestedScrollingViews funktioniert. Dies ist ein bekannter Fehler \u2013 Abhilfe schafft folgendes Snippet. Damit ist es nun auch m\u00f6glich, zu View-Elementen zu scrollen, die sich innerhalb einer NestedScrollingView befinden.<\/p>\n<pre class=\"minimize:true lang:java decode:true\" title=\"NestedScrollToAction\">\/**\r\n\r\n * Improved {@link android.support.test.espresso.action.ScrollToAction} which works with\r\n\r\n * {@link NestedScrollView}\r\n\r\n *\/\r\n\r\npublic final class NestedScrollToAction implements ViewAction {\r\n\r\n    @SuppressWarnings(\"unchecked\")\r\n\r\n    @Override\r\n\r\n    public Matcher&lt;View&gt; getConstraints() {\r\n\r\n        return allOf(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), isDescendantOfA(anyOf(\r\n\r\n                isAssignableFrom(ScrollView.class), isAssignableFrom(HorizontalScrollView.class),\r\n\r\n                isAssignableFrom(NestedScrollView.class))));\r\n\r\n    }\r\n\r\n    @Override\r\n\r\n    public void perform(UiController uiController, View view) {\r\n\r\n        if (isDisplayingAtLeast(90).matches(view)) {\r\n\r\n            return;\r\n\r\n        }\r\n\r\n        Rect rect = new Rect();\r\n\r\n        view.getDrawingRect(rect);\r\n\r\n        if (!view.requestRectangleOnScreen(rect, true \/* immediate *\/)) {\r\n\r\n            Log.w(\"nestedScrollAction\", \"Scrolling to view was requested, but none of the parents scrolled.\");\r\n\r\n        }\r\n\r\n        uiController.loopMainThreadUntilIdle();\r\n\r\n        if (!isDisplayingAtLeast(90).matches(view)) {\r\n\r\n            throw new PerformException.Builder()\r\n\r\n                    .withActionDescription(this.getDescription())\r\n\r\n                    .withViewDescription(HumanReadables.describe(view))\r\n\r\n                    .withCause(new RuntimeException(\r\n\r\n                            \"Scrolling to view was attempted, but the view is not displayed\"))\r\n\r\n                    .build();\r\n\r\n        }\r\n\r\n    }\r\n\r\n    @Override\r\n\r\n    public String getDescription() {\r\n\r\n        return \"scroll to\";\r\n\r\n    }\r\n\r\n}\r\n\r\n\/\/Convenient Methode, welche statt scrollTo() verwendet werden kann\r\n\r\npublic static ViewAction betterScrollTo() {\r\n\r\n    return ViewActions.actionWithAssertions(new NestedScrollToAction());\r\n\r\n}<\/pre>\n<h3><span class=\"ez-toc-section\" id=\"CheckboxenRadio-Buttons\"><\/span>Checkboxen\/Radio Buttons<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Auch die Verwendung von Checkboxen\/Radio Buttons innerhalb von Tests ist nicht trivial. Android Studio generiert beim Testen von Checkboxen\/Radio Buttons Code, der so leider nicht funktioniert. Der Code f\u00fchrt zwar ein click() aus, die View ist dadurch allerdings nicht <em>checked<\/em>. Aber auch hier gibt es Abhilfe:<\/p>\n<pre class=\"minimize:true lang:java decode:true\" title=\"setChecked ViewAction\">public static ViewAction setChecked(final boolean checked) {\r\n\r\n    return new ViewAction() {\r\n\r\n        @Override\r\n\r\n        public BaseMatcher&lt;View&gt; getConstraints() {\r\n\r\n            return new BaseMatcher&lt;View&gt;() {\r\n\r\n                @Override\r\n\r\n                public boolean matches(Object item) {\r\n\r\n                    return isA(Checkable.class).matches(item);\r\n\r\n                }\r\n\r\n                @Override\r\n\r\n                public void describeMismatch(Object item, Description mismatchDescription) {}\r\n\r\n                @Override\r\n\r\n                public void describeTo(Description description) {}\r\n\r\n            };\r\n\r\n        }\r\n\r\n        @Override\r\n\r\n        public String getDescription() { return null; }\r\n\r\n        @Override\r\n\r\n        public void perform(UiController uiController, View view) {\r\n\r\n            Checkable checkableView = (Checkable) view;\r\n\r\n            checkableView.setChecked(checked);\r\n\r\n        }\r\n\r\n    };\r\n\r\n}<\/pre>\n<p>Den gesamten Quellcode sowie weitere Funktionen die hier und da Abhilfe zu bekannten Problemen schaffen k\u00f6nnen, mit entsprechender Beispiel Applikation findet ihr auf unserem <a href=\"https:\/\/github.com\/inovex\/android-espresso-example\">Github Profil<\/a>.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Firebase\"><\/span>Firebase<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Zu guter Letzt soll auch das von Google entwickelte Firebase Testing Lab kurz Erw\u00e4hnung finden. Dieses erm\u00f6glicht es, eure Tests auf verschiedenen (echten) Ger\u00e4ten auszuf\u00fchren. Zur Verf\u00fcgung stehen die meisten Flagship-Ger\u00e4te mit z.T verschiedenen API Leveln. Das kostenlose Kontingent an Ausf\u00fchrungen ist relativ beschr\u00e4nkt \u2013 man kann Tests nur 1x am Tag auf 5 echten Ger\u00e4ten ausf\u00fchren \u2014 aber dennoch eine gute Sache, um das Angebot zu testen.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2845\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/fb1.png\" alt=\"\" width=\"763\" height=\"357\" \/> <img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2846\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/fb2.png\" alt=\"\" width=\"768\" height=\"409\" \/> <img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2847\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/fb3.png\" alt=\"\" width=\"1205\" height=\"339\" \/><\/p>\n<div style=\"margin: 7px; padding: 7px; border-left: 6px solid #9CCD00;\">\n<h2><span class=\"ez-toc-section\" id=\"Verstaerkung-gesucht\"><\/span>Verst\u00e4rkung gesucht!<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Ihr seid selbst begeisterte Android-Entwickler und auf der Suche nach neuen Herausforderungen? Wir stellen in Karlsruhe, Pforzheim, Stuttgart, M\u00fcnchen, K\u00f6ln und Hamburg derzeit besonders Android-Embedded-Entwickler ein, bieten euch aber auch als PraktikantInnen oder WerkstudentInnen Einblicke in das Entwicklerleben. Ihr wollt eure Abschlussarbeit im Bereich Software-Entwicklung schreiben? Auch das k\u00f6nnt ihr bei uns! Und wenn euch besonders der Feinschliff von Software am Herzen liegt, bewerbt euch als Digital Quality Advocat!<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Obwohl sich das Espresso Framework schon seit l\u00e4ngerer Zeit zum Standard f\u00fcr UI-Tests unter Android etabliert hat, ist die H\u00fcrde noch immer recht hoch diese auch zu implementieren. Durch den Espresso Test Recorder, der mit Android Studio 2.2 eingef\u00fchrt wurde, hat sich diese Schwierigkeit deutlich verringert. Wir wollen uns also damit besch\u00e4ftigen, wie wir relativ [&hellip;]<\/p>\n","protected":false},"author":56,"featured_media":12973,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"ep_exclude_from_search":false,"footnotes":""},"tags":[510],"service":[420],"coauthors":[{"id":56,"display_name":"Christopher Jakob","user_nicename":"cjakob"}],"class_list":["post-21051","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-apps-2","service-apps"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Android UI Tests mit dem Espresso Test Recorder<\/title>\n<meta name=\"description\" content=\"In diesem Artikel besch\u00e4ftigen wir uns damit, wie wir relativ einfach UI-Tests generieren aber auch unabh\u00e4ngig von Remote-Servern machen k\u00f6nnen.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Android UI Tests mit dem Espresso Test Recorder\" \/>\n<meta property=\"og:description\" content=\"In diesem Artikel besch\u00e4ftigen wir uns damit, wie wir relativ einfach UI-Tests generieren aber auch unabh\u00e4ngig von Remote-Servern machen k\u00f6nnen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/\" \/>\n<meta property=\"og:site_name\" content=\"inovex GmbH\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/inovexde\" \/>\n<meta property=\"article:published_time\" content=\"2017-03-22T13:58:52+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-03-23T11:25:52+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/android-testing.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2300\" \/>\n\t<meta property=\"og:image:height\" content=\"678\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Christopher Jakob\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/android-testing-1024x302.png\" \/>\n<meta name=\"twitter:creator\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:site\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Christopher Jakob\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"9\u00a0Minuten\" \/>\n\t<meta name=\"twitter:label3\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data3\" content=\"Christopher Jakob\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/\"},\"author\":{\"name\":\"Christopher Jakob\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/c266a0abd8422c5cabc881b84740beba\"},\"headline\":\"Android UI Tests mit dem Espresso Test Recorder und einem Mock Web Server\",\"datePublished\":\"2017-03-22T13:58:52+00:00\",\"dateModified\":\"2026-03-23T11:25:52+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/\"},\"wordCount\":1275,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/android-testing.png\",\"keywords\":[\"Apps\"],\"articleSection\":[\"Applications\",\"General\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/\",\"url\":\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/\",\"name\":\"Android UI Tests mit dem Espresso Test Recorder\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/android-testing.png\",\"datePublished\":\"2017-03-22T13:58:52+00:00\",\"dateModified\":\"2026-03-23T11:25:52+00:00\",\"description\":\"In diesem Artikel besch\u00e4ftigen wir uns damit, wie wir relativ einfach UI-Tests generieren aber auch unabh\u00e4ngig von Remote-Servern machen k\u00f6nnen.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#primaryimage\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/android-testing.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/android-testing.png\",\"width\":2300,\"height\":678,\"caption\":\"Android Testing Mockup\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.inovex.de\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Android UI Tests mit dem Espresso Test Recorder und einem Mock Web Server\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.inovex.de\/de\/#website\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"name\":\"inovex GmbH\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.inovex.de\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\",\"name\":\"inovex GmbH\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"width\":1921,\"height\":1081,\"caption\":\"inovex GmbH\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/inovexde\",\"https:\/\/x.com\/inovexgmbh\",\"https:\/\/www.instagram.com\/inovexlife\/\",\"https:\/\/www.linkedin.com\/company\/inovex\",\"https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/c266a0abd8422c5cabc881b84740beba\",\"name\":\"Christopher Jakob\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/1410dc23bb681b59bd0017eb27d50541\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/3d0f657dd7efee2b54cd0e7793e61f2eac1b93735fc6614e1c172c5135075e1e?s=96&d=retro&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/3d0f657dd7efee2b54cd0e7793e61f2eac1b93735fc6614e1c172c5135075e1e?s=96&d=retro&r=g\",\"caption\":\"Christopher Jakob\"},\"url\":\"https:\/\/www.inovex.de\/de\/blog\/author\/cjakob\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Android UI Tests mit dem Espresso Test Recorder","description":"In diesem Artikel besch\u00e4ftigen wir uns damit, wie wir relativ einfach UI-Tests generieren aber auch unabh\u00e4ngig von Remote-Servern machen k\u00f6nnen.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/","og_locale":"de_DE","og_type":"article","og_title":"Android UI Tests mit dem Espresso Test Recorder","og_description":"In diesem Artikel besch\u00e4ftigen wir uns damit, wie wir relativ einfach UI-Tests generieren aber auch unabh\u00e4ngig von Remote-Servern machen k\u00f6nnen.","og_url":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/","og_site_name":"inovex GmbH","article_publisher":"https:\/\/www.facebook.com\/inovexde","article_published_time":"2017-03-22T13:58:52+00:00","article_modified_time":"2026-03-23T11:25:52+00:00","og_image":[{"width":2300,"height":678,"url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/android-testing.png","type":"image\/png"}],"author":"Christopher Jakob","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/android-testing-1024x302.png","twitter_creator":"@inovexgmbh","twitter_site":"@inovexgmbh","twitter_misc":{"Verfasst von":"Christopher Jakob","Gesch\u00e4tzte Lesezeit":"9\u00a0Minuten","Written by":"Christopher Jakob"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#article","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/"},"author":{"name":"Christopher Jakob","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/c266a0abd8422c5cabc881b84740beba"},"headline":"Android UI Tests mit dem Espresso Test Recorder und einem Mock Web Server","datePublished":"2017-03-22T13:58:52+00:00","dateModified":"2026-03-23T11:25:52+00:00","mainEntityOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/"},"wordCount":1275,"commentCount":0,"publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/android-testing.png","keywords":["Apps"],"articleSection":["Applications","General"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/","url":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/","name":"Android UI Tests mit dem Espresso Test Recorder","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#primaryimage"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/android-testing.png","datePublished":"2017-03-22T13:58:52+00:00","dateModified":"2026-03-23T11:25:52+00:00","description":"In diesem Artikel besch\u00e4ftigen wir uns damit, wie wir relativ einfach UI-Tests generieren aber auch unabh\u00e4ngig von Remote-Servern machen k\u00f6nnen.","breadcrumb":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#primaryimage","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/android-testing.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/03\/android-testing.png","width":2300,"height":678,"caption":"Android Testing Mockup"},{"@type":"BreadcrumbList","@id":"https:\/\/www.inovex.de\/de\/blog\/android-ui-tests\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.inovex.de\/de\/"},{"@type":"ListItem","position":2,"name":"Android UI Tests mit dem Espresso Test Recorder und einem Mock Web Server"}]},{"@type":"WebSite","@id":"https:\/\/www.inovex.de\/de\/#website","url":"https:\/\/www.inovex.de\/de\/","name":"inovex GmbH","description":"","publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.inovex.de\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/www.inovex.de\/de\/#organization","name":"inovex GmbH","url":"https:\/\/www.inovex.de\/de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","width":1921,"height":1081,"caption":"inovex GmbH"},"image":{"@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/inovexde","https:\/\/x.com\/inovexgmbh","https:\/\/www.instagram.com\/inovexlife\/","https:\/\/www.linkedin.com\/company\/inovex","https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ"]},{"@type":"Person","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/c266a0abd8422c5cabc881b84740beba","name":"Christopher Jakob","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/1410dc23bb681b59bd0017eb27d50541","url":"https:\/\/secure.gravatar.com\/avatar\/3d0f657dd7efee2b54cd0e7793e61f2eac1b93735fc6614e1c172c5135075e1e?s=96&d=retro&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/3d0f657dd7efee2b54cd0e7793e61f2eac1b93735fc6614e1c172c5135075e1e?s=96&d=retro&r=g","caption":"Christopher Jakob"},"url":"https:\/\/www.inovex.de\/de\/blog\/author\/cjakob\/"}]}},"_links":{"self":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/21051","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/users\/56"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/comments?post=21051"}],"version-history":[{"count":5,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/21051\/revisions"}],"predecessor-version":[{"id":66668,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/21051\/revisions\/66668"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media\/12973"}],"wp:attachment":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media?parent=21051"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/tags?post=21051"},{"taxonomy":"service","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/service?post=21051"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/coauthors?post=21051"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}