Zoeken…


Opmerkingen

Espresso

Espresso spiekbriefje helpt je bij het schrijven van je tests en wat je wilt testen:

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

De officiële documentatie is ook altijd een goede plaats voor referentie:

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

Geavanceerde espresso-videosuggesties van Google: https://www.youtube.com/watch?v=isihPOY2vS4

Probleemoplossen

  • Wanneer u probeert te scrollen, moet u eerst het toetsenbord sluiten:

Let op: het gebruik van de "Espresso" -versie doet niets als het buiten een ViewAction wordt gebruikt. Dit is misschien niet vanzelfsprekend als je een import in de ViewAction-versie hebt, omdat ze exact dezelfde methode hebben.

ViewActions.closeSoftKeyboard;
Espresso.closeSoftKeyboard();
  • Wanneer u tests in een suite in plaats van individueel uitvoert, moet u er rekening mee houden dat de activiteit van de vorige test mogelijk nog steeds wordt uitgevoerd. Vertrouw er niet op dat de vorige test opDestroy () wordt aangeroepen vóór de huidige tests opResume (). Het blijkt dat dit eigenlijk een bug is : http://b.android.com/201513

Espresso instellen

build.gradle in het build.gradle bestand van uw Android-app-module de volgende afhankelijkheden toe:

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

Geef de AndroidJUnitRunner voor de parameter testInstrumentationRunner in het bestand build.gradle .

android {

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

}

Voeg bovendien deze afhankelijkheid toe voor het bieden van ondersteuning voor opzettelijke bespotting

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

En voeg deze toe voor ondersteuning voor het testen van webviews

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

Maak een Espresso-testklasse

Plaats de volgende Java-klasse in src / androidTest / java en voer deze uit.

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
  }

}

Open Sluiten LadeLayout

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 eenvoudige UI-test

UI testtools

Twee belangrijke tools die tegenwoordig het meest worden gebruikt voor UI-testen zijn Appium en Espresso.

Appium Espresso
blackbox-test witte / grijze doos testen
wat je ziet is wat je kunt testen kan de interne werking van de app wijzigen en voorbereiden voor het testen, bijvoorbeeld wat gegevens opslaan in de database of gedeelde voorkeuren voordat de test wordt uitgevoerd
meestal gebruikt voor integratie end-to-end tests en volledige gebruikersstromen testen van de functionaliteit van een scherm en / of stroom
kan worden geabstraheerd, zodat een geschreven test kan worden uitgevoerd op iOS en Android Alleen Android
goed ondersteund goed ondersteund
ondersteunt parallel testen op meerdere apparaten met seleniumrooster Plug-ins zoals Spoon bestaan niet uit de doos, maar bestaan totdat er echte Google-ondersteuning uitkomt

Hoe espresso aan het project toe te voegen

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

OPMERKING Als u de nieuwste ondersteuningsbibliotheken, annotaties enz. Gebruikt, moet u de oudere versies van espresso uitsluiten om botsingen te voorkomen:

    // 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'
    }

Afgezien van deze invoer is het noodzakelijk om Android-instrumentatietestagent toe te voegen aan build.gradle android.defaultConfig:

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

Apparaat set up

Voor niet-schilferige tests wordt het aanbevolen om de volgende instellingen op uw apparaten in te stellen:

  • Opties voor ontwikkelaars / Animaties uitschakelen - vermindert schilferigheid van tests
  • Opties voor ontwikkelaars / Blijf wakker - als u speciale apparaten voor tests hebt, is dit nuttig
  • Opties voor ontwikkelaars / logboekbuffergroottes - stel deze in op een hoger aantal als u zeer grote testpakketten op uw telefoon uitvoert
  • Toegankelijkheid / Touch & Hold-vertraging - lang om problemen met het tikken in espresso te voorkomen

Nogal een setup van de echte wereld ha? Welnu, als dat uit de weg is, laten we eens kijken hoe je een kleine test kunt instellen

Het schrijven van de test

Laten we aannemen dat we het volgende scherm hebben: Klein scherm voor espressotest Het scherm bevat:

  • tekstinvoerveld - R.id.textEntry
  • knop die snackbar met getypte tekst toont wanneer erop wordt geklikt - R.id.shownSnackbarBtn
  • snackbar die door de gebruiker getypte tekst moet bevatten - android.support.design.R.id.snackbar_text

Laten we nu een klasse maken die onze flow test:

/**
* 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()));
    }
}

Zoals je hebt gemerkt, zijn er 3-4 dingen die je vaak opmerkt:

onView (withXYZ) <- viewMatchers waarmee u elementen op het scherm kunt vinden

perform (klik ()) <- viewActions, u kunt acties uitvoeren op elementen die u eerder hebt gevonden

check (wedstrijden (isDisplayed ()))) <- viewAssertions, controles die u wilt uitvoeren op schermen die u eerder hebt gevonden

Al deze en vele anderen zijn hier te vinden: https://google.github.io/android-testing-support-library/docs/espresso/cheatsheet/index.html

Dat is alles, nu kunt u de test uitvoeren door met de rechtermuisknop op de klassennaam / test te klikken en Test uitvoeren te selecteren of met een opdracht:

./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()));
}

Houd er rekening mee dat dit een tijdelijke oplossing is en in botsing komt met andere weergaven met dezelfde inhoudsbeschrijving.

Een actie uitvoeren op een weergave

Het is mogelijk om ViewActions op een view uit te voeren met de uitvoeringsmethode.
De klasse ViewActions biedt ViewActions voor de meest voorkomende acties, zoals:

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

Om bijvoorbeeld op de weergave te klikken:

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

U kunt meer dan één actie uitvoeren met één oproep uitvoeren:

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

Als de weergave waarmee u werkt zich in een ScrollView (verticaal of horizontaal) bevindt, kunt u eerdere acties overwegen waarbij de weergave moet worden weergegeven (zoals click() en typeText() ) met scrollTo() . Dit zorgt ervoor dat de weergave wordt weergegeven voordat u verdergaat met de andere actie:

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

Een weergave vinden met onView

Met ViewMatchers kunt u de weergave vinden in de huidige weergavehiërarchie.

Gebruik de methode onView() om een view te vinden met een view-matcher die de juiste view selecteert. De methoden onView() retourneren een object van het type ViewInteraction .

Het vinden van een weergave door zijn R.id is bijvoorbeeld zo eenvoudig als:

onView(withId(R.id.my_view))

Een weergave zoeken met een tekst:

onView(withText("Hello World"))

Aangepaste espresso-matchers

Espresso heeft standaard veel matchers die u helpen bij het vinden van weergaven die u nodig hebt om enkele controles of interacties met hen uit te voeren.

De belangrijkste zijn te vinden op het volgende cheatsheet:

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

Enkele voorbeelden van matchers zijn:

  • withId (R.id.ID_of_object_you_are_looking_for);
  • withText ("Sommige tekst die u van een object verwacht");
  • isDisplayed () <- controleer of de weergave zichtbaar is
  • doesNotExist () <- controleer of de weergave niet bestaat

Al deze zijn erg handig voor dagelijks gebruik, maar als je complexere weergaven hebt, kunnen je aangepaste matchers de tests leesbaarder maken en je kunt ze op verschillende plaatsen hergebruiken.

Er zijn 2 meest voorkomende type matchers die je kunt uitbreiden: TypeSafeMatcher BoundedMatcher

Als u TypeSafeMatcher implementeert, moet u het exemplaar controleren van de weergave waartegen u beweert, als het het juiste type is, vergelijkt u sommige van de eigenschappen met een waarde die u aan een matcher hebt opgegeven.

Typ bijvoorbeeld veilig zoeken dat een afbeeldingsweergave valideert, correct kan worden getekend:

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("]");
        }
    }
}

Het gebruik van de matcher kan als volgt worden ingepakt:

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

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

Bounded matchers zijn vergelijkbaar, u hoeft de typecontrole niet uit te voeren, maar aangezien dat automatisch voor u gebeurt:

 /**
 * 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());
        }
    };
}

Meer over matchers is te lezen op:

http://hamcrest.org/

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

Algehele espresso

Espresso instellen:

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

ViewMatchers - Een verzameling objecten die Matcher<? super View> implementeren Matcher<? super View> interface. U kunt een of meer hiervan onView aan de methode onView om een weergave binnen de huidige weergavehiërarchie te vinden.

ViewActions - Een verzameling ViewActions die kan worden doorgegeven aan de ViewInteraction.perform() -methode ( click() bijvoorbeeld click() ).

ViewAssertions - Een verzameling ViewAssertions die kan worden doorgegeven via de methode ViewInteraction.check() . Meestal gebruikt u de overeenkomst-bewering, die een View-matcher gebruikt om de status van de momenteel geselecteerde weergave te bevestigen.


Espresso spiekbriefje van Google

voer hier de afbeeldingsbeschrijving in


Voer tekst in in EditText

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

Uitvoeren Klik op Beeld

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

Bezig met controleren van weergave wordt weergegeven

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

Groepeer een verzameling testklassen in een testpakket

U kunt de uitvoering organiseren van uw instrumentele eenheidstests die een Suite definiëren.

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

Vervolgens kunt u in AndroidStudio met gradle werken of een nieuwe configuratie instellen, zoals:

voer hier de afbeeldingsbeschrijving in

Testpakketten kunnen worden genest.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow