Suche…


Bemerkungen

Espresso

Espresso Spickzettel hilft Ihnen, Ihre Tests zu schreiben und was Sie testen möchten:

https://google.github.io/android-testing-support-library/docs/espresso/cheatsheet/

Ein guter Bezugspunkt ist auch immer die offizielle Dokumentation:

https://google.github.io/android-testing-support-library/docs/espresso/index.html

Fortgeschrittene Espresso-Video-Vorschläge von Google: https://www.youtube.com/watch?v=isihPOY2vS4

Fehlerbehebung

  • Schließen Sie beim Scrollen unbedingt die Tastatur:

Achtung: Wenn Sie die "Espresso" -Version nicht verwenden, können Sie nichts tun, wenn Sie sie außerhalb einer ViewAction verwenden. Dies ist möglicherweise nicht offensichtlich, wenn Sie einen Import in der ViewAction-Version haben, da sie exakt denselben Methodennamen haben.

ViewActions.closeSoftKeyboard;
Espresso.closeSoftKeyboard();
  • Wenn Sie Tests in einer Suite statt einzeln ausführen, beachten Sie, dass die Aktivität des vorherigen Tests möglicherweise noch ausgeführt wird. Verlassen Sie sich nicht darauf, dass onDestroy () des vorherigen Tests vor den aktuellen Tests onResume () aufgerufen wird. Es stellt sich heraus, dass dies tatsächlich ein Fehler ist : http://b.android.com/201513

Espresso einrichten

build.gradle Sie in der build.gradle Datei Ihres Android-App-Moduls die nächsten Abhängigkeiten hinzu:

dependencies {   
    // Android JUnit Runner     
    androidTestCompile 'com.android.support.test:runner:0.5'
    // JUnit4 Rules
    androidTestCompile 'com.android.support.test:rules:0.5'
    // Espresso core
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
    // Espresso-contrib for DatePicker, RecyclerView, Drawer actions, Accessibility checks, CountingIdlingResource
    androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2.2'
    //UI Automator tests
    androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.2.2'
}

AndroidJUnitRunner den AndroidJUnitRunner für den Parameter testInstrumentationRunner in der Datei build.gradle .

android {

  defaultConfig {
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  }

}

Fügen Sie außerdem diese Abhängigkeit hinzu, um Unterstützung für Vorspiegelungen bereitzustellen

androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'

Fügen Sie diese Option für die Unterstützung von Webview-Tests hinzu

// Espresso-web for WebView support
androidTestCompile 'com.android.support.test.espresso:espresso-web:2.2.2'

Erstellen Sie eine Espresso-Testklasse

Legen Sie die nächste Java-Klasse in src / androidTest / java ab und führen Sie sie aus.

public class UITest {

  @Test public void Simple_Test() {
    onView(withId(R.id.my_view))         // withId(R.id.my_view) is a ViewMatcher
        .perform(click())                // click() is a ViewAction
        .check(matches(isDisplayed()));  // matches(isDisplayed()) is a ViewAssertion
  }

}

Öffnen Sie das DrawerLayout

public final class DrawerLayoutTest  {

  @Test public void Open_Close_Drawer_Layout() {
    onView(withId(R.id.drawer_layout)).perform(actionOpenDrawer());
    onView(withId(R.id.drawer_layout)).perform(actionCloseDrawer());
  }

  public static ViewAction actionOpenDrawer() {
    return new ViewAction() {
      @Override public Matcher<View> getConstraints() {
        return isAssignableFrom(DrawerLayout.class);
      }

      @Override public String getDescription() {
        return "open drawer";
      }

      @Override public void perform(UiController uiController, View view) {
        ((DrawerLayout) view).openDrawer(GravityCompat.START);
      }
    };
  }

  public static ViewAction actionCloseDrawer() {
    return new ViewAction() {
      @Override public Matcher<View> getConstraints() {
        return isAssignableFrom(DrawerLayout.class);
      }

      @Override public String getDescription() {
        return "close drawer";
      }

      @Override public void perform(UiController uiController, View view) {
        ((DrawerLayout) view).closeDrawer(GravityCompat.START);
      }
    };
  }
  
}

Espresso einfacher UI-Test

UI-Testwerkzeuge

Zwei Hauptwerkzeuge, die heutzutage hauptsächlich für UI-Tests verwendet werden, sind Appium und Espresso.

Appium Espresso
Blackbox-Test weiße / graue Boxprüfung
Was Sie sehen, ist das, was Sie testen können kann die inneren Abläufe der App ändern und für den Test vorbereiten, z. B. vor dem Ausführen des Tests einige Daten in einer Datenbank oder gemeinsam genutzte Präferenzen speichern
wird hauptsächlich für Integrations-End-to-End-Tests und gesamte Benutzerflüsse verwendet Testen der Funktionalität eines Bildschirms und / oder Flusses
kann abstrahiert werden, so dass der geschriebene Test auf iOS und Android ausgeführt werden kann Nur Android
gut unterstützt gut unterstützt
unterstützt parallele Tests an mehreren Geräten mit Selengitter Parallele Tests sind nicht möglich, Plugins wie Spoon sind vorhanden, bis echte Unterstützung von Google herauskommt

So fügen Sie Espresso zum Projekt hinzu

dependencies {
  // Set this dependency so you can use Android JUnit Runner
  androidTestCompile 'com.android.support.test:runner:0.5'
  // Set this dependency to use JUnit 4 rules
  androidTestCompile 'com.android.support.test:rules:0.5'
  // Set this dependency to build and run Espresso tests
  androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
  // Set this dependency to build and run UI Automator tests
  androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.2.2'
}

HINWEIS Wenn Sie die neuesten Support-Bibliotheken, Anmerkungen usw. verwenden, müssen Sie ältere Versionen von Espresso ausschließen, um Kollisionen zu vermeiden:

    // there is a conflict with the test support library (see http://stackoverflow.com/questions/29857695)
    // so for now re exclude the support-annotations dependency from here to avoid clashes
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2') {
        exclude group: 'com.android.support', module: 'support-annotations'
        exclude module: 'support-annotations'
        exclude module: 'recyclerview-v7'
        exclude module: 'support-v4'
        exclude module: 'support-v7'
    }
    // exclude a couple of more modules here because of <http://stackoverflow.com/questions/29216327> and
    // more specifically of <https://code.google.com/p/android-test-kit/issues/detail?id=139>
    // otherwise you'll receive weird crashes on devices and dex exceptions on emulators
    // Espresso-contrib for DatePicker, RecyclerView, Drawer actions, Accessibility checks, CountingIdlingResource
    androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.2.2') {
        exclude group: 'com.android.support', module: 'support-annotations'
        exclude group: 'com.android.support', module: 'design'
        exclude module: 'support-annotations'
        exclude module: 'recyclerview-v7'
        exclude module: 'support-v4'
        exclude module: 'support-v7'
    }
    //excluded specific packages due to https://code.google.com/p/android/issues/detail?id=183454
    androidTestCompile('com.android.support.test.espresso:espresso-intents:2.2.2') {
        exclude group: 'com.android.support', module: 'support-annotations'
        exclude module: 'support-annotations'
        exclude module: 'recyclerview-v7'
        exclude module: 'support-v4'
        exclude module: 'support-v7'
    }

    androidTestCompile('com.android.support.test.espresso:espresso-web:2.2.2') {
        exclude group: 'com.android.support', module: 'support-annotations'
        exclude module: 'support-annotations'
        exclude module: 'recyclerview-v7'
        exclude module: 'support-v4'
        exclude module: 'support-v7'
    }

    androidTestCompile('com.android.support.test:runner:0.5') {
        exclude group: 'com.android.support', module: 'support-annotations'
        exclude module: 'support-annotations'
        exclude module: 'recyclerview-v7'
        exclude module: 'support-v4'
        exclude module: 'support-v7'
    }
    androidTestCompile('com.android.support.test:rules:0.5') {
        exclude group: 'com.android.support', module: 'support-annotations'
        exclude module: 'support-annotations'
        exclude module: 'recyclerview-v7'
        exclude module: 'support-v4'
        exclude module: 'support-v7'
    }

Abgesehen von diesen Importen ist es erforderlich, Android-Testläufer zu build.gradle android.defaultConfig hinzuzufügen:

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

Gerätkonfiguration

Für nicht flockige Tests wird empfohlen, die folgenden Einstellungen an Ihren Geräten vorzunehmen:

  • Entwickleroptionen / Animationen deaktivieren - reduziert die Flakynität von Tests
  • Entwickleroptionen / Wach bleiben - wenn Sie dedizierte Geräte für Tests haben, ist dies nützlich
  • Entwickleroptionen / Logger-Puffergrößen: Legen Sie eine höhere Anzahl fest, wenn Sie sehr große Testreihen auf Ihrem Telefon ausführen
  • Accessibility / Touch & Hold-Verzögerung - lang, um Probleme beim Tippen auf Espresso zu vermeiden

Ziemlich ein Setup aus der realen Welt? Nun, wenn das nicht möglich ist, werfen wir einen Blick auf die Einrichtung eines kleinen Tests

Test schreiben

Nehmen wir an, wir haben den folgenden Bildschirm: Kleiner Bildschirm für den Espresso-Test Der Bildschirm enthält:

  • Texteingabefeld - R.id.textEntry
  • Schaltfläche, die die Snackbar mit eingetipptem Text anzeigt - R.id.shownSnackbarBtn
  • Snackbar, die den vom Benutzer eingegebenen Text enthalten sollte - android.support.design.R.id.snackbar_text

Lassen Sie uns nun eine Klasse erstellen, die unseren Fluss testet:

/**
* Testing of the snackbar activity.
**/
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SnackbarActivityTest{
    //espresso rule which tells which activity to start
    @Rule
    public final ActivityTestRule<SnackbarActivity> mActivityRule = 
        new ActivityTestRule<>(SnackbarActivity.class, true, false);


    @Override
    public void tearDown() throws Exception {
        super.tearDown();
        //just an example how tear down should cleanup after itself
        mDatabase.clear();
        mSharedPrefs.clear();
    }
    
    @Override
    public void setUp() throws Exception {
        super.setUp();
        //setting up your application, for example if you need to have a user in shared
        //preferences to stay logged in you can do that for all tests in your setup
        User mUser = new User();
        mUser.setToken("randomToken");
    }
    
    /**
    *Test methods should always start with "testXYZ" and it is a good idea to 
    *name them after the intent what you want to test
    **/
    @Test
    public void testSnackbarIsShown() {
        //start our activity
        mActivityRule.launchActivity(null);
        //check is our text entry displayed and enter some text to it
        String textToType="new snackbar text";
        onView(withId(R.id.textEntry)).check(matches(isDisplayed()));
        onView(withId(R.id.textEntry)).perform(typeText(textToType));
        //click the button to show the snackbar
        onView(withId(R.id.shownSnackbarBtn)).perform(click());
        //assert that a view with snackbar_id with text which we typed and is displayed
        onView(allOf(withId(android.support.design.R.id.snackbar_text), 
        withText(textToType))) .check(matches(isDisplayed()));
    }
}

Wie Sie bemerkt haben, gibt es 3-4 Dinge, die Sie häufig bemerken:

onView (withXYZ) <- viewMatchers Mit diesen können Sie Elemente auf dem Bildschirm finden

perform (click ()) <- viewActions, Sie können Aktionen für Elemente ausführen, die Sie zuvor gefunden haben

check (matches (isDisplayed ())) <- viewAssertions: Überprüft, ob Sie die zuvor gefundenen Bildschirme ausführen möchten

Alle diese und viele andere finden Sie hier: https://google.github.io/android-testing-support-library/docs/espresso/cheatsheet/index.html

Jetzt können Sie den Test ausführen, indem Sie mit der rechten Maustaste auf den Klassennamen / Test klicken und Test ausführen oder mit dem Befehl auswählen:

./gradlew connectedFLAVORNAMEAndroidTest
@Test
public void testUpNavigation() {
    intending(hasComponent(ParentActivity.class.getName())).respondWith(new Instrumentation.ActivityResult(0, null));

    onView(withContentDescription("Navigate up")).perform(click());

    intended(hasComponent(ParentActivity.class.getName()));
}

Beachten Sie, dass dies eine Problemumgehung ist und mit anderen Ansichten kollidieren wird, die dieselbe Inhaltsbeschreibung haben.

Ausführen einer Aktion für eine Ansicht

Es ist möglich, ViewActions für eine Ansicht mithilfe der Perform-Methode auszuführen.
Die ViewActions Klasse stellt ViewActions für die häufigsten Aktionen bereit, z.

ViewActions.click()
ViewActions.typeText()
ViewActions.clearText()

Um zum Beispiel auf die Ansicht zu klicken:

onView(...).perform(click());
onView(withId(R.id.button_simple)).perform(click());

Sie können mehrere Aktionen mit einem Perform-Aufruf ausführen:

onView(...).perform(typeText("Hello"), click());

Wenn sich die Ansicht, mit der Sie arbeiten, in einer ScrollView (vertikal oder horizontal) befindet, sollten Sie vorhergehende Aktionen in Betracht ziehen, die eine Anzeige der Ansicht (wie click() und typeText() ) mit scrollTo() . Dadurch wird sichergestellt, dass die Ansicht angezeigt wird, bevor mit der anderen Aktion fortgefahren wird:

onView(...).perform(scrollTo(), click());

Eine Ansicht mit onView finden

Mit den ViewMatchers können Sie Ansichten in der aktuellen Ansichtshierarchie finden.

Um eine Ansicht zu finden, verwenden Sie die Methode onView() mit einem View Matcher, der die richtige Ansicht auswählt. Die onView() -Methoden geben ein Objekt vom Typ ViewInteraction .

Zum Beispiel ist es so einfach, eine Ansicht anhand ihrer R.id :

onView(withId(R.id.my_view))

Eine Ansicht mit einem Text suchen:

onView(withText("Hello World"))

Espresso benutzerdefinierte Matchers

Espresso verfügt standardmäßig über viele Übereinstimmungen, mit deren Hilfe Sie Ansichten finden, die Sie für einige Überprüfungen oder Interaktionen mit ihnen benötigen.

Die wichtigsten finden Sie im folgenden Spickzettel:

https://google.github.io/android-testing-support-library/docs/espresso/cheatsheet/

Einige Beispiele für Matcher sind:

  • withId (R.id.ID_of_object_you_are_looking_for);
  • withText ("Text, den Sie für ein Objekt erwarten");
  • isDisplayed () <- Prüfen Sie, ob die Ansicht sichtbar ist
  • doesNotExist () <- Überprüfen Sie, ob die Ansicht nicht vorhanden ist

All dies ist sehr nützlich für den täglichen Gebrauch. Wenn Sie jedoch komplexere Ansichten haben, können Ihre benutzerdefinierten Matcher die Tests lesbarer machen und sie an verschiedenen Stellen wiederverwenden.

Es gibt zwei gängige Typen von Matchern, die Sie erweitern können: TypeSafeMatcher BoundedMatcher

Um TypeSafeMatcher zu implementieren, müssen Sie die Instanz überprüfen. Wenn die Ansicht, für die Sie eine Bestätigung ausführen, der richtige Typ ist, in dem Sie einige ihrer Eigenschaften mit einem Wert vergleichen, den Sie einem Matcher bereitgestellt haben.

Geben Sie zum Beispiel sicheres Matcher ein, das eine Bildansicht überprüft.

public class DrawableMatcher extends TypeSafeMatcher<View> {

    private @DrawableRes final int expectedId;
    String resourceName;
    
    public DrawableMatcher(@DrawableRes int expectedId) {
        super(View.class);
        this.expectedId = expectedId;
    }

    @Override
    protected boolean matchesSafely(View target) {
        //Type check we need to do in TypeSafeMatcher
        if (!(target instanceof ImageView)) {
            return false;
        }
        //We fetch the image view from the focused view
        ImageView imageView = (ImageView) target;
        if (expectedId < 0) {
            return imageView.getDrawable() == null;
        }
        //We get the drawable from the resources that we are going to compare with image view source
        Resources resources = target.getContext().getResources();
        Drawable expectedDrawable = resources.getDrawable(expectedId);
        resourceName = resources.getResourceEntryName(expectedId);

        if (expectedDrawable == null) {
            return false;
        }
        //comparing the bitmaps should give results of the matcher if they are equal
        Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
        Bitmap otherBitmap = ((BitmapDrawable) expectedDrawable).getBitmap();
        return bitmap.sameAs(otherBitmap);
    }


    @Override
    public void describeTo(Description description) {
        description.appendText("with drawable from resource id: ");
        description.appendValue(expectedId);
        if (resourceName != null) {
            description.appendText("[");
            description.appendText(resourceName);
            description.appendText("]");
        }
    }
}

Die Verwendung des Streichholzspielers könnte folgendermaßen dargestellt werden:

  public static Matcher<View> withDrawable(final int resourceId) {
    return new DrawableMatcher(resourceId);
}

 onView(withDrawable(R.drawable.someDrawable)).check(matches(isDisplayed()));

Bounded Matcher sind ähnlich, Sie müssen die Typprüfung jedoch nicht durchführen, da dies jedoch automatisch für Sie erledigt wird:

 /**
 * Matches a {@link TextInputFormView}'s input hint with the given resource ID
 *
 * @param stringId
 * @return
 */
public static Matcher<View> withTextInputHint(@StringRes final int stringId) {
    return new BoundedMatcher<View, TextInputFormView>(TextInputFormView.class) {
        private String mResourceName = null;

        @Override
        public void describeTo(final Description description) {
            //fill these out properly so your logging and error reporting is more clear
            description.appendText("with TextInputFormView that has hint ");
            description.appendValue(stringId);
            if (null != mResourceName) {
                description.appendText("[");
                description.appendText(mResourceName);
                description.appendText("]");
            }
        }

        @Override
        public boolean matchesSafely(final TextInputFormView view) {
            if (null == mResourceName) {
                try {
                    mResourceName = view.getResources().getResourceEntryName(stringId);
                } catch (Resources.NotFoundException e) {
                    throw new IllegalStateException("could not find string with ID " + stringId, e);
                }
            }
            return view.getResources().getString(stringId).equals(view.getHint());
        }
    };
}

Weitere Informationen zu Matchern finden Sie unter:

http://hamcrest.org/

https://developer.android.com/reference/android/support/test/espresso/matcher/ViewMatchers.html

Insgesamt Espresso

Setup Espresso:

androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
androidTestCompile 'com.android.support.test:runner:0.5'

ViewMatchers - Eine Sammlung von Objekten, die Matcher<? super View> implementieren Matcher<? super View> Schnittstelle. Sie können eine oder mehrere davon an die onView Methode übergeben, um eine Ansicht in der aktuellen Ansichtshierarchie zu onView .

ViewActions - Eine Auflistung von ViewActions , die an die ViewInteraction.perform() Methode übergeben werden können (z. B. click() ).

ViewAssertions - Eine Auflistung von ViewAssertions , an die die ViewInteraction.check() -Methode übergeben werden kann. In den meisten Fällen verwenden Sie die Übereinstimmungsassertion, bei der mithilfe eines View-Matchers der Status der aktuell ausgewählten Ansicht bestätigt wird.


Espresso Spickzettel von Google

Geben Sie hier die Bildbeschreibung ein


Geben Sie Text in EditText ein

onView(withId(R.id.edt_name)).perform(typeText("XYZ"));
        closeSoftKeyboard();

Ausführen Klicken Sie auf Ansicht

 onView(withId(R.id.btn_id)).perform(click());

Überprüfen der Ansicht wird angezeigt

 onView(withId(R.id.edt_pan_number)).check(ViewAssertions.matches((isDisplayed())));

Gruppieren Sie eine Sammlung von Testklassen in einer Testsuite

Sie können die Ausführung Ihrer instrumentierten Komponententests zur Definition einer Suite organisieren .

/**
 * Runs all unit tests.
 */
@RunWith(Suite.class)
@Suite.SuiteClasses({MyTest1.class , 
         MyTest2.class, 
         MyTest3.class})
public class AndroidTestSuite {}

In AndroidStudio können Sie dann Gradle ausführen oder eine neue Konfiguration festlegen, z.

Geben Sie hier die Bildbeschreibung ein

Testsuiten können verschachtelt sein.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow