Szukaj…


Uwagi

Espresso

Ściągawka do espresso pomoże Ci napisać testy i to, co chcesz przetestować:

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

Również zawsze dobrym miejscem odniesienia jest oficjalna dokumentacja:

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

Zaawansowane propozycje filmów espresso od Google: https://www.youtube.com/watch?v=isihPOY2vS4

Rozwiązywanie problemów

  • Podczas próby przewijania pamiętaj, aby najpierw zamknąć klawiaturę:

Uwaga: niestosowanie wersji „Espresso” nic nie zrobi, jeśli zostanie użyte poza ViewAction. Może to nie być oczywiste, jeśli masz import w wersji ViewAction, ponieważ mają one dokładnie taką samą nazwę metody.

ViewActions.closeSoftKeyboard;
Espresso.closeSoftKeyboard();
  • Podczas uruchamiania testów razem w pakiecie, a nie pojedynczo, należy pamiętać, że działanie z poprzedniego testu może być nadal uruchomione. Nie polegaj na wywołaniu onDestroy () poprzedniego testu przed bieżącymi testami onResume (). Okazuje się, że to w rzeczywistości błąd : http://b.android.com/201513

Skonfiguruj espresso

W pliku build.gradle modułu aplikacji na Androida dodaj kolejne zależności:

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

Podaj parametr AndroidJUnitRunner dla parametru testInstrumentationRunner w pliku build.gradle .

android {

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

}

Dodatkowo dodaj tę zależność, aby zapewnić zamierzoną obsługę drwiny

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

I dodaj ten do wsparcia testowania webview

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

Utwórz klasę testową espresso

Umieść następną klasę Java w src / androidTest / java i uruchom ją.

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
  }

}

Otwórz Zamknij szufladę

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

Prosty test interfejsu użytkownika espresso

Narzędzia do testowania interfejsu użytkownika

Dwa główne narzędzia, które są obecnie najczęściej używane do testowania interfejsu użytkownika, to Appium i Espresso.

Appium Espresso
test blackbox testowanie białych / szarych skrzynek
to, co widzisz, możesz przetestować potrafi zmienić wewnętrzne działanie aplikacji i przygotować ją do testowania, np. zapisać niektóre dane w bazie danych lub wspólne preferencje przed uruchomieniem testu
używane głównie w testach integracyjnych od końca do końca i przepływach użytkowników testowanie funkcjonalności ekranu i / lub przepływu
można wyodrębnić, aby napisany test można było wykonać na iOS i Androidzie Tylko Android
dobrze wspierany dobrze wspierany
obsługuje równoległe testowanie na wielu urządzeniach z siatką selenową Nie jest gotowe do testowania równoległego, wtyczki takie jak Spoon istnieją, dopóki nie pojawi się prawdziwa obsługa Google

Jak dodać espresso do projektu

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

UWAGA Jeśli używasz najnowszych bibliotek wsparcia, adnotacji itp., Musisz wykluczyć starsze wersje z espresso, aby uniknąć kolizji:

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

Oprócz tych importów konieczne jest dodanie narzędzia testującego Androida do build.gradle android.defaultConfig:

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

Konfiguracja urządzenia

W przypadku testu niestabilnego zaleca się ustawienie następujących ustawień na urządzeniach:

  • Opcje programistyczne / Wyłącz animacje - zmniejsza kruchość testów
  • Opcje programistyczne / Czuwaj - jeśli masz dedykowane urządzenia do testów, jest to przydatne
  • Opcje programistyczne / Rozmiary buforów rejestratora - ustaw na wyższą liczbę, jeśli uruchomisz na telefonie bardzo duże pakiety testowe
  • Dostępność / Opóźnienie dotyku i przytrzymania - długie, aby uniknąć problemów z pukaniem w espresso

Całkiem konfiguracja z prawdziwego świata ha? Cóż, teraz, gdy to nie przeszkadza, zobaczmy, jak skonfigurować mały test

Pisanie testu

Załóżmy, że mamy następujący ekran: Ekran Smple do testu espresso Ekran zawiera:

  • pole wprowadzania tekstu - R.id.textEntry
  • przycisk wyświetlający pasek kliknięcia z tekstem wpisanym po kliknięciu - R.id.shownSnackbarBtn
  • pasek przekąska, który powinien zawierać tekst wpisany przez użytkownika - android.support.design.R.id.snackbar_text

Teraz stwórzmy klasę, która przetestuje nasz przepływ:

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

Jak zauważyłeś, pojawiają się 3-4 rzeczy, które możesz zauważyć często:

onView (withXYZ) <- viewMatchers Za ich pomocą można znaleźć elementy na ekranie

perform (click ()) <- viewActions, możesz wykonywać akcje na elementach, które wcześniej znalazłeś

check (mecze (isDisplayed ())) <- viewAssertions, sprawdza, co chcesz zrobić na ekranach wcześniej znalezionych

Wszystkie te i wiele innych można znaleźć tutaj: https://google.github.io/android-testing-support-library/docs/espresso/cheatsheet/index.html

To wszystko, teraz możesz uruchomić test, klikając prawym przyciskiem myszy nazwę klasy / test i wybierając Uruchom test lub za pomocą polecenia:

./gradlew connectedFLAVORNAMEAndroidTest

Nawigacja w górę

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

Pamiętaj, że jest to obejście i będzie kolidować z innymi widokami o tym samym opisie treści.

Wykonywanie akcji w widoku

Możliwe jest wykonywanie funkcji ViewActions w widoku za pomocą metody perform.
Klasa ViewActions zapewnia metody pomocnicze dla najczęstszych akcji, takich jak:

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

Na przykład, aby kliknąć widok:

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

Możesz wykonać więcej niż jedną akcję, wykonując jedno połączenie:

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

Jeśli widok, z którym pracujesz, znajduje się w ScrollView (pionowym lub poziomym), rozważ wcześniejsze działania wymagające wyświetlenia widoku (takie jak click() i typeText() ) za pomocą scrollTo() . Zapewnia to wyświetlenie widoku przed przejściem do innej akcji:

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

Znajdowanie widoku za pomocą onView

Dzięki ViewMatchers możesz znaleźć widok w bieżącej hierarchii widoków.

Aby znaleźć widok, użyj metody onView() z dopasowaniem widoku, który wybiera prawidłowy widok. Metody onView() zwracają obiekt typu ViewInteraction .

Na przykład znalezienie widoku przez jego R.id jest tak proste, jak:

onView(withId(R.id.my_view))

Znajdowanie widoku z tekstem:

onView(withText("Hello World"))

Niestandardowe elementy dopasowujące espresso

Domyślnie Espresso ma wiele dopasowań, które pomagają znaleźć widoki, które należy wykonać, aby sprawdzić niektóre z nich.

Najważniejsze z nich można znaleźć w następującym ściągu:

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

Oto niektóre przykłady dopasowań:

  • withId (R.id.ID_of_object_you_are_looking_for);
  • withText („Niektóre teksty, które mają mieć obiekt”);
  • isDisplayed () <- sprawdź, czy widok jest widoczny
  • doesNotExist () <- sprawdź, czy widok nie istnieje

Wszystkie te są bardzo przydatne w codziennym użytkowaniu, ale jeśli masz bardziej złożone widoki, pisanie niestandardowych dopasowań może sprawić, że testy będą bardziej czytelne i możesz ich ponownie użyć w różnych miejscach.

Istnieją dwa najpopularniejsze typy dopasowywania, które można rozszerzyć: TypeSafeMatcher BoundedMatcher

Implementacja TypeSafeMatcher wymaga sprawdzenia instancji widoku, przeciwko któremu twierdzisz, jeśli jest to poprawny typ, dopasujesz niektóre jego właściwości do wartości podanej przez ciebie do dopasowywania.

Na przykład wpisz Bezpieczny moduł dopasowujący, który sprawdza poprawność widoku obrazu, ma poprawny rysunek:

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

Użycie modułu dopasowywania może być opakowane w następujący sposób:

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

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

Dopasowane ograniczenia są podobne, po prostu nie musisz sprawdzać typu, ale ponieważ jest to zrobione automatycznie:

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

Więcej na temat dopasujących można przeczytać na:

http://hamcrest.org/

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

Ogólnie Espresso

Ustaw espresso:

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

ViewMatchers - Zbiór obiektów, które implementują Matcher<? super View> interfejs. Możesz przekazać jeden lub więcej z nich do metody onView , aby zlokalizować widok w bieżącej hierarchii widoków.

ViewActions - kolekcja ViewActions które można przekazać do metody ViewInteraction.perform() (na przykład click() ).

ViewAssertions - kolekcja ViewAssertions które można przekazać za ViewInteraction.check() metody ViewInteraction.check() . Przez większość czasu będziesz używał asercji dopasowania, która używa dopasowywania widoku do potwierdzenia stanu aktualnie wybranego widoku.


Ściągawka do espresso firmy Google

wprowadź opis zdjęcia tutaj


Wpisz tekst w EditText

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

Wykonaj Kliknij na Widok

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

Sprawdzanie widoku jest wyświetlane

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

Zgrupuj kolekcję klas testowych w zestawie testów

Możesz zorganizować wykonanie testowanych testów jednostkowych definiujących pakiet .

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

Następnie w AndroidStudio możesz uruchomić gradle lub ustawić nową konfigurację, taką jak:

wprowadź opis zdjęcia tutaj

Zestawy testowe można zagnieżdżać.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow