Recherche…


Remarques

Expresso

La feuille de triche expresso vous aidera à écrire vos tests et ce que vous voulez tester:

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

La documentation officielle est toujours un bon endroit pour référence:

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

Suggestions avancées de vidéos expresso par Google: https://www.youtube.com/watch?v=isihPOY2vS4

Dépannage

  • Lorsque vous essayez de faire défiler, veillez à fermer le clavier en premier:

Watchout: ne pas utiliser la version "Espresso" ne fera rien en dehors de ViewAction. Cela peut ne pas être évident si vous avez une importation sur la version de ViewAction, car ils ont exactement le même nom de méthode.

ViewActions.closeSoftKeyboard;
Espresso.closeSoftKeyboard();
  • Lorsque vous exécutez des tests ensemble dans une suite plutôt qu'individuellement, sachez que l'activité du test précédent est peut-être toujours en cours d'exécution. Ne vous fiez pas à l'appel du test précédent onDestroy () avant les tests en cours onResume (). Il s'avère que c'est en fait un bogue : http://b.android.com/201513

Configurer Espresso

Dans le fichier build.gradle de votre module d'application Android, ajoutez les prochaines dépendances:

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

Spécifiez AndroidJUnitRunner pour le paramètre testInstrumentationRunner dans le fichier build.gradle .

android {

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

}

En outre, ajoutez cette dépendance pour fournir une prise en charge intentionnelle

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

Et ajoutez celui-ci pour la prise en charge des tests WebView

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

Créer une classe de test expresso

Placez la classe java suivante dans src / androidTest / java et lancez-la.

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
  }

}

Ouvrir Fermer 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);
      }
    };
  }
  
}

Test de l'interface utilisateur simple expresso

Outils de test de l'interface utilisateur

Appium et Espresso sont les deux principaux outils actuellement utilisés pour les tests d’interface utilisateur.

Appium Expresso
test de blackbox test de boîte blanche / grise
ce que vous voyez est ce que vous pouvez tester peut modifier le fonctionnement interne de l'application et le préparer pour le test, par exemple enregistrer certaines données dans la base de données ou les préférences partagées avant de lancer le test
Utilisé principalement pour des tests d'intégration de bout en bout et des flux d'utilisateurs entiers tester la fonctionnalité d'un écran et / ou d'un flux
peut être abstraite afin que le test écrit puisse être exécuté sur iOS et Android Android uniquement
Bien soutenu Bien soutenu
prend en charge les tests parallèles sur plusieurs périphériques avec grille de sélénium Pas de tests parallèles prêts à l'emploi, des plug-ins comme Spoon existent jusqu'à ce que le véritable support de Google apparaisse

Comment ajouter du café au projet

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

REMARQUE Si vous utilisez les dernières bibliothèques de support, les annotations, etc., vous devez exclure les anciennes versions de l'espresso pour éviter les collisions:

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

Outre ces importations, il est nécessaire d’ajouter le testeur d’instrumentation Android à build.gradle android.defaultConfig:

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

Configuration de l'appareil

Pour un test non feuilleté, il est recommandé de définir les paramètres suivants sur vos appareils:

  • Options pour les développeurs / Désactiver les animations - réduit la fragilité des tests
  • Options pour les développeurs / Restez éveillé - si vous avez des appareils dédiés aux tests, cela est utile
  • Options du développeur / Taille du tampon de l'enregistreur - définissez un nombre plus élevé si vous exécutez des suites de test très volumineuses sur votre téléphone
  • Délai d'accessibilité / Touch & Hold - long pour éviter les problèmes de tapotement dans l'espresso

Assez une configuration du monde réel ha? Eh bien, maintenant, quand c'est hors de portée permet de jeter un oeil à la configuration d'un petit test

Écrire le test

Supposons que nous avons l'écran suivant: Écran tamisé pour le test d'espresso L'écran contient:

  • champ de saisie de texte - R.id.textEntry
  • bouton qui montre le snack avec le texte tapé quand cliqué - R.id.shownSnackbarBtn
  • snackbar qui devrait contenir le texte saisi par l'utilisateur - android.support.design.R.id.snackbar_text

Maintenant, créons une classe qui testera notre flux:

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

Comme vous l'avez remarqué, il y a 3 ou 4 choses que vous remarquerez souvent:

onView (withXYZ) <- viewMatchers avec eux, vous pouvez trouver des éléments à l'écran

effectuer (click ()) <- viewActions, vous pouvez exécuter des actions sur des éléments trouvés précédemment

check (correspond à (isDisplayed ())) <- viewAssertions, vérifications à effectuer sur les écrans précédemment trouvés

Tous ces éléments et bien d'autres peuvent être trouvés ici: https://google.github.io/android-testing-support-library/docs/espresso/cheatsheet/index.html

Thats it, maintenant vous pouvez exécuter le test soit avec un clic droit sur le nom de la classe / test et en sélectionnant Exécuter le test ou avec la commande:

./gradlew connectedFLAVORNAMEAndroidTest

La navigation

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

Notez qu'il s'agit d'une solution de contournement et qu'elle entrera en conflit avec d'autres vues ayant la même description de contenu.

Effectuer une action sur une vue

Il est possible d'effectuer des ViewActions sur une vue en utilisant la méthode perform.
La classe ViewActions fournit des méthodes d'assistance pour les actions les plus courantes, telles que:

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

Par exemple, pour cliquer sur la vue:

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

Vous pouvez exécuter plusieurs actions avec un seul appel:

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

Si la vue avec laquelle vous travaillez est située dans un ScrollView (vertical ou horizontal), considérez les actions précédentes qui nécessitent l'affichage de la vue (comme click() et typeText() ) avec scrollTo() . Cela garantit que la vue est affichée avant de passer à l'autre action:

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

Trouver une vue avec onView

Avec ViewMatchers vous pouvez voir la vue dans la hiérarchie de la vue actuelle.

Pour rechercher une vue, utilisez la méthode onView() avec un observateur de vue qui sélectionne la vue correcte. Les méthodes onView() renvoient un objet de type ViewInteraction .

Par exemple, trouver une vue par son R.id est aussi simple que:

onView(withId(R.id.my_view))

Trouver une vue avec un texte:

onView(withText("Hello World"))

Espresso personnalisés

Espresso par défaut a beaucoup de correspondances qui vous aident à trouver des vues dont vous avez besoin pour faire des vérifications ou des interactions avec eux.

Les plus importants peuvent être trouvés dans la feuille de triche suivante:

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

Voici quelques exemples d’apparieurs:

  • avecId (R.id.ID_of_object_you_are_looking_for);
  • withText ("Du texte que vous attendez d'un objet");
  • isDisplayed () <- check est la vue visible
  • doesNotExist () <- vérifie que la vue n'existe pas

Tous ces éléments sont très utiles pour un usage quotidien, mais si vous avez des vues plus complexes, les personnaliseurs peuvent rendre les tests plus lisibles et les réutiliser à différents endroits.

Il y a 2 types les plus communs d'allumeurs que vous pouvez étendre: TypeSafeMatcher BoundedMatcher

L'implémentation de TypeSafeMatcher nécessite que vous vérifiiez l'instance de la vue à laquelle vous vous engagez, si le type correct correspond à certaines de ses propriétés par rapport à une valeur que vous avez fournie à un analyseur.

Par exemple, le gestionnaire de type sécurisé qui valide une vue d'image peut être dessiné correctement:

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

L'utilisation du matcher pourrait être comme ceci:

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

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

Les corrélateurs liés sont similaires mais vous n'avez pas à faire de vérification de type mais, puisque cela se fait automatiquement pour vous:

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

Plus sur les matchers peuvent être lus sur:

http://hamcrest.org/

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

Espresso globale

Configurer Espresso:

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

ViewMatchers - Une collection d'objets qui implémentent Matcher<? super View> interface. Vous pouvez en transmettre une ou plusieurs à la méthode onView pour localiser une vue dans la hiérarchie de vues actuelle.

ViewActions - Collection de ViewActions pouvant être transmise à la méthode ViewInteraction.perform() (par exemple, click() ).

ViewAssertions - Une collection de ViewAssertions pouvant être passée à la méthode ViewInteraction.check() . La plupart du temps, vous utiliserez l'assertion de correspondances, qui utilise un analyseur de vues pour déterminer l'état de la vue actuellement sélectionnée.


Feuillet d'espresso par google

entrer la description de l'image ici


Entrer du texte dans EditText

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

Effectuez Cliquez sur Afficher

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

La vue de vérification est affichée

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

Grouper une collection de classes de test dans une suite de tests

Vous pouvez organiser l'exécution de vos tests unitaires instrumentés définissant une Suite .

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

Ensuite, dans AndroidStudio, vous pouvez exécuter avec gradle ou définir une nouvelle configuration comme:

entrer la description de l'image ici

Les suites de tests peuvent être imbriquées.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow