Pisanie automatycznych testów za pomocą Automatora UI

Automator UI to platforma do testowania UI odpowiednia do testowania funkcjonalnego interfejsu między aplikacjami w systemie i w aplikacjach zainstalowanych. Interfejsy API Automator pozwalają wchodzić w interakcje z widocznymi elementami na urządzeniu, niezależnie od tego, które z nich Activity jest aktywne. Dzięki temu można wykonywać takie działania jak otwieranie menu Ustawienia czy uruchamianie aplikacji na urządzeniu testowym. W ramach testu można wyszukiwać element interfejsu za pomocą wygodnych deskryptorów, np. tekstu wyświetlanego w tym komponencie lub jego opisu treści.

Platforma testowania Automatyzatora UI to interfejs API oparty na narzędziach i współpracuje z uruchamiającym testem AndroidJUnitRunner. Dobrze sprawdza się w przypadku nieprzezroczystych testów automatycznych, których kod testów nie zależy od wewnętrznych szczegółów implementacji aplikacji docelowej.

Najważniejsze funkcje środowiska testowego Automatyzatora UI to m.in.:

Dostęp do stanu urządzenia

Platforma testowania Automatyzatora UI udostępnia klasę UiDevice, która umożliwia dostęp do urządzenia, na którym działa aplikacja docelowa, i wykonywanie na nim operacji. Możesz wywoływać jej metody, aby uzyskać dostęp do właściwości urządzenia, takich jak bieżąca orientacja czy rozmiar wyświetlacza. Klasa UiDevice pozwala też wykonywać te działania:

  1. Zmień ustawienie obrotu urządzenia.
  2. Naciśnij klawisze sprzętowe, np. „zwiększ głośność”.
  3. Naciśnij przycisk Wstecz, Ekran główny lub Menu.
  4. Otwórz obszar powiadomień.
  5. Zrób zrzut ekranu bieżącego okna.

Aby np. symulować naciśnięcie przycisku ekranu głównego, wywołaj metodę UiDevice.pressHome().

Interfejsy API Automator

Interfejsy API Automatora umożliwiają pisanie rzetelnych testów bez znajomości szczegółów implementacji aplikacji, na którą kierujesz reklamy. Te interfejsy API pozwalają przechwytywać komponenty UI i manipulować nimi w wielu aplikacjach:

  • UiObject2: reprezentuje element interfejsu widoczny na urządzeniu.
  • BySelector: określa kryteria dopasowania elementów interfejsu.
  • By: tworzy BySelector w zwięzły sposób.
  • Configurator: pozwala ustawić kluczowe parametry do uruchamiania testów Automatyzatora UI.

Na przykład ten kod pokazuje, jak można napisać skrypt testowy, który otwiera aplikację Gmail na urządzeniu:

Kotlin


device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
device.pressHome()

val gmail: UiObject2 = device.findObject(By.text("Gmail"))
// Perform a click and wait until the app is opened.
val opened: Boolean = gmail.clickAndWait(Until.newWindow(), 3000)
assertThat(opened).isTrue()

Java


device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
device.pressHome();

UiObject2 gmail = device.findObject(By.text("Gmail"));
// Perform a click and wait until the app is opened.
Boolean opened = gmail.clickAndWait(Until.newWindow(), 3000);
assertTrue(opened);

Skonfiguruj Automatyzatora UI

Zanim utworzysz test interfejsu użytkownika za pomocą Automatora interfejsu, skonfiguruj lokalizację kodu źródłowego i zależności projektu testowego zgodnie z opisem w sekcji Konfigurowanie projektu na potrzeby testu AndroidX.

W pliku build.gradle modułu aplikacji na Androida ustaw odniesienie do zależności z biblioteką Automator interfejsu:

Kotlin

dependencies {
  ...
  androidTestImplementation('androidx.test.uiautomator:uiautomator:2.3.0-alpha03')
}

Odlotowy

dependencies {
  ...
  androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.3.0-alpha03'
}

Aby zoptymalizować testowanie przez działanie Automatyzatora UI, najpierw sprawdź komponenty interfejsu aplikacji docelowej i upewnij się, że są dostępne. Te wskazówki optymalizacyjne opisaliśmy w 2 kolejnych sekcjach.

Sprawdzanie UI na urządzeniu

Przed zaprojektowaniem testu sprawdź komponenty UI widoczne na urządzeniu. Aby mieć pewność, że testy Automatyzatora interfejsu mają dostęp do tych komponentów, sprawdź, czy mają widoczne etykiety tekstowe, wartości android:contentDescription lub oba te elementy.

Narzędzie uiautomatorviewer to wygodny interfejs wizualny, który pozwala sprawdzić hierarchię układu i wyświetlić właściwości komponentów UI widocznych na pierwszym planie urządzenia. Te informacje pozwalają tworzyć bardziej szczegółowe testy za pomocą Automatora UI. Można np. utworzyć selektor interfejsu, który odpowiada określonej widocznej właściwości.

Aby uruchomić narzędzie uiautomatorviewer:

  1. Uruchom docelową aplikację na urządzeniu fizycznym.
  2. Podłącz urządzenie do komputera do programowania.
  3. Otwórz okno terminala i przejdź do katalogu <android-sdk>/tools/.
  4. Uruchom narzędzie za pomocą tego polecenia:
 $ uiautomatorviewer

Aby wyświetlić właściwości interfejsu aplikacji:

  1. W interfejsie uiautomatorviewer kliknij przycisk Zrzut ekranu urządzenia.
  2. Najedź kursorem na zrzut w panelu po lewej stronie, aby wyświetlić komponenty interfejsu zidentyfikowane przez narzędzie uiautomatorviewer. Właściwości są wymienione w panelu w prawym dolnym rogu, a w hierarchii układu – w panelu w prawym górnym rogu.
  3. Opcjonalnie kliknij przycisk Przełącz węzły NAF, aby wyświetlić komponenty UI niedostępne dla Automatora UI. W przypadku tych komponentów dostępne mogą być tylko niektóre informacje.

Informacje o typowych typach komponentów interfejsu dostępnych w Androidzie znajdziesz w artykule Interfejs użytkownika.

Upewnij się, że informacje o Twojej aktywności są dostępne

Platforma testowa Automator interfejsu działa lepiej w aplikacjach z zaimplementowanymi ułatwieniami dostępu na Androidzie. Gdy używasz elementów interfejsu typu View lub podklasy View z pakietu SDK, nie musisz implementować obsługi ułatwień dostępu, ponieważ te klasy zrobiły to już za Ciebie.

Niektóre aplikacje korzystają jednak z niestandardowych elementów interfejsu, by zwiększyć wygodę użytkowników. Takie elementy nie zapewniają automatycznej obsługi ułatwień dostępu. Jeśli Twoja aplikacja zawiera wystąpienia podklasy View, które nie pochodzą z pakietu SDK, dodaj do tych elementów ułatwienia dostępu, wykonując te czynności:

  1. Utwórz konkretne zajęcia, które rozszerzają zakres ExploreByTouchHelper.
  2. Powiąż instancję nowej klasy z określonym niestandardowym elementem interfejsu, wywołując funkcję setAccessibilityDelegate().

Dodatkowe wskazówki dotyczące dodawania ułatwień dostępu do elementów widoków niestandardowych znajdziesz w artykule o tworzeniu widoków niestandardowych z dostępem do ułatwień dostępu. Więcej informacji o ogólnych sprawdzonych metodach dotyczących ułatwień dostępu na Androidzie znajdziesz w artykule Zwiększanie dostępności aplikacji.

Tworzenie klasy testowej Automator interfejsu

Klasa testowa Automator interfejsu użytkownika powinna być napisana w taki sam sposób jak klasa testowa JUnit 4. Więcej informacji o tworzeniu klas testowych JUnit 4 oraz używaniu asercji i adnotacji JUnit 4 znajdziesz w artykule Tworzenie instrumentowanej klasy testów jednostkowych.

Dodaj adnotację @RunWith(AndroidJUnit4.class) na początku definicji klasy testowej. Musisz też wskazać klasę AndroidJUnitRunner dostępną w narzędziu AndroidX Test jako domyślny system uruchamiający testy. Szczegółowo opisujemy ten krok w artykule Przeprowadzanie testów Automatora UI na urządzeniu lub w emulatorze.

Zaimplementuj ten model programowania w klasie testowej Automator interfejsu:

  1. Pobierz obiekt UiDevice, aby uzyskać dostęp do urządzenia, które chcesz przetestować. Aby to zrobić, wywołaj metodę getInstance() i przekaż go jako argument obiekt Instrumentation.
  2. Pobierz obiekt UiObject2, aby uzyskać dostęp do komponentu interfejsu wyświetlanego na urządzeniu (np. bieżącego widoku na pierwszym planie) przez wywołanie metody findObject().
  3. Symulowanie konkretnej interakcji użytkownika z danym komponentem interfejsu przez wywołanie metody UiObject2. Może to być np. wywołanie scrollUntil() w celu przewijania lub setText(), które pozwala edytować pole tekstowe. Interfejsy API w krokach 2 i 3 możesz wywoływać wielokrotnie w razie potrzeby, aby przetestować bardziej złożone interakcje użytkownika, które obejmują wiele komponentów UI lub sekwencje działań użytkownika.
  4. Po wykonaniu tych interakcji użytkowników sprawdź, czy interfejs przedstawia oczekiwany stan i sposób działania.

Szczegółowy opis tych czynności znajdziesz w poniższych sekcjach.

Dostęp do komponentów interfejsu

Obiekt UiDevice to główny sposób uzyskiwania dostępu do stanu urządzenia i modyfikowania go. W testach możesz wywoływać metody UiDevice, aby sprawdzić stan różnych właściwości, takich jak bieżąca orientacja czy rozmiar wyświetlacza. Test może używać obiektu UiDevice do wykonywania działań na poziomie urządzenia, takich jak wymuszanie wykonania określonego obrotu, naciśnięcie przycisków na padzie kierunkowym oraz przycisków ekranu głównego i menu.

Dobrą praktyką jest rozpoczynanie testu na ekranie głównym urządzenia. Na ekranie głównym (lub w innej lokalizacji początkowej wybranej na urządzeniu) możesz wywoływać metody udostępniane przez interfejs UI Automator API, aby wybierać elementy interfejsu i wchodzić z nimi w interakcje.

Ten fragment kodu pokazuje, jak w ramach testu można uzyskać wystąpienie UiDevice i symulować naciśnięcie przycisku ekranu głównego:

Kotlin


import org.junit.Before
import androidx.test.runner.AndroidJUnit4
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
...

private const val BASIC_SAMPLE_PACKAGE = "com.example.android.testing.uiautomator.BasicSample"
private const val LAUNCH_TIMEOUT = 5000L
private const val STRING_TO_BE_TYPED = "UiAutomator"

@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = 18)
class ChangeTextBehaviorTest2 {

private lateinit var device: UiDevice

@Before
fun startMainActivityFromHomeScreen() {
  // Initialize UiDevice instance
  device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

  // Start from the home screen
  device.pressHome()

  // Wait for launcher
  val launcherPackage: String = device.launcherPackageName
  assertThat(launcherPackage, notNullValue())
  device.wait(
    Until.hasObject(By.pkg(launcherPackage).depth(0)),
    LAUNCH_TIMEOUT
  )

  // Launch the app
  val context = ApplicationProvider.getApplicationContext<Context>()
  val intent = context.packageManager.getLaunchIntentForPackage(
  BASIC_SAMPLE_PACKAGE).apply {
    // Clear out any previous instances
    addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
  }
  context.startActivity(intent)

  // Wait for the app to appear
  device.wait(
    Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
    LAUNCH_TIMEOUT
    )
  }
}

Java


import org.junit.Before;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.Until;
...

@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = 18)
public class ChangeTextBehaviorTest {

  private static final String BASIC_SAMPLE_PACKAGE
  = "com.example.android.testing.uiautomator.BasicSample";
  private static final int LAUNCH_TIMEOUT = 5000;
  private static final String STRING_TO_BE_TYPED = "UiAutomator";
  private UiDevice device;

  @Before
  public void startMainActivityFromHomeScreen() {
    // Initialize UiDevice instance
    device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

    // Start from the home screen
    device.pressHome();

    // Wait for launcher
    final String launcherPackage = device.getLauncherPackageName();
    assertThat(launcherPackage, notNullValue());
    device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)),
    LAUNCH_TIMEOUT);

    // Launch the app
    Context context = ApplicationProvider.getApplicationContext();
    final Intent intent = context.getPackageManager()
    .getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE);
    // Clear out any previous instances
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
    context.startActivity(intent);

    // Wait for the app to appear
    device.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
    LAUNCH_TIMEOUT);
    }
}

W przykładzie instrukcja @SdkSuppress(minSdkVersion = 18) pomaga zapewnić, że testy będą przeprowadzane tylko na urządzeniach z Androidem 4.3 (poziom interfejsu API 18) lub nowszym, zgodnie z wymaganiami platformy UI Automator.

Metoda findObject() pozwala pobrać obiekt UiObject2, który reprezentuje widok spełniający określone kryteria selektora. W razie potrzeby możesz ponownie używać instancji UiObject2 utworzonych przez siebie na innych etapach testowania aplikacji. Pamiętaj, że platforma testowa Automatyzatora UI przeszukuje bieżący wyświetlacz pod kątem dopasowania za każdym razem, gdy w teście kliknięcie elementu interfejsu lub zapytania dotyczącego właściwości obejmuje wystąpienie UiObject2.

Poniższy fragment kodu pokazuje, jak test może utworzyć instancje UiObject2 reprezentujące przycisk Anuluj i przycisk OK w aplikacji.

Kotlin


val okButton: UiObject2 = device.findObject(
    By.text("OK").clazz("android.widget.Button")
)

// Simulate a user-click on the OK button, if found.
if (okButton != null) {
    okButton.click()
}

Java


UiObject2 okButton = device.findObject(
    By.text("OK").clazz("android.widget.Button")
);

// Simulate a user-click on the OK button, if found.
if (okButton != null) {
    okButton.click();
}

Określ selektor

Jeśli chcesz uzyskać dostęp do określonego komponentu interfejsu w aplikacji, użyj klasy By do utworzenia wystąpienia BySelector. BySelector reprezentuje zapytanie o konkretne elementy wyświetlanego interfejsu.

Jeśli zostanie znaleziony więcej niż 1 pasujący element, jako docelowy UiObject2 zwracany jest pierwszy pasujący element w hierarchii układu. Podczas tworzenia obiektu BySelector możesz połączyć kilka właściwości, aby zawęzić wyszukiwanie. Jeśli nie znajdzie pasującego elementu interfejsu, zwracany jest element null.

Aby zagnieździć wiele instancji BySelector, możesz użyć metody hasChild() lub hasDescendant(). Na przykład ten przykładowy kod pokazuje, jak podczas testu można określić wyszukiwanie, aby znaleźć pierwszy element ListView zawierający podrzędny element interfejsu z właściwością tekstową.

Kotlin


val listView: UiObject2 = device.findObject(
    By.clazz("android.widget.ListView")
        .hasChild(
            By.text("Apps")
        )
)

Java


UiObject2 listView = device.findObject(
    By.clazz("android.widget.ListView")
        .hasChild(
            By.text("Apps")
        )
);

Stan obiektu możesz określić w kryteriach selektora. Jeśli np. chcesz wybrać listę wszystkich zaznaczonych elementów, aby je odznaczyć, wywołaj metodę checked() z argumentem ustawionym na „prawda”.

Wykonywanie działań

Gdy test uzyska obiekt UiObject2, możesz wywołać metody w klasie UiObject2, aby wykonywać interakcje użytkowników w reprezentowanym przez ten obiekt komponencie interfejsu użytkownika. Możesz określić, takie działania jak:

  • click() : klika środek widocznych granic elementu interfejsu.
  • drag() : przeciąga obiekt do dowolnych współrzędnych.
  • setText() : umieszcza tekst w polu do edycji po wyczyszczeniu jego zawartości. I na odwrót: metoda clear() czyści istniejący tekst w polu możliwym do edytowania.
  • swipe() : przesuwanie palcem w określonym kierunku.
  • scrollUntil(): wykonuje przewijanie w kierunku określonego kierunku, dopóki nie zostaną spełnione kryteria Condition lub EventCondition.

Platforma testowa Automatora UI umożliwia wysyłanie intencji lub uruchamianie aktywności bez używania poleceń powłoki za pomocą pobierania obiektu Kontekst za pomocą getContext().

Ten fragment kodu pokazuje, jak podczas testu można użyć intencji do uruchomienia testowanej aplikacji. Ta metoda jest przydatna, gdy chcesz przetestować tylko aplikację Kalkulator i nie interesuje Cię program uruchamiający.

Kotlin


fun setUp() {
...

  // Launch a simple calculator app
  val context = getInstrumentation().context
  val intent = context.packageManager.getLaunchIntentForPackage(CALC_PACKAGE).apply {
    addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
  }
  // Clear out any previous instances
  context.startActivity(intent)
  device.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT)
}

Java


public void setUp() {
...

  // Launch a simple calculator app
  Context context = getInstrumentation().getContext();
  Intent intent = context.getPackageManager()
  .getLaunchIntentForPackage(CALC_PACKAGE);
  intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);

  // Clear out any previous instances
  context.startActivity(intent);
  device.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT);
}

Sprawdź wyniki

Parametr InstrumentationTestCase rozszerza zakres TestCase, dzięki czemu możesz użyć standardowych metod JUnit Assert, aby przetestować, czy komponenty interfejsu użytkownika w aplikacji zwracają oczekiwane wyniki.

Ten fragment kodu pokazuje, jak podczas testu znaleźć kilka przycisków w aplikacji Kalkulator, klikać je po kolei i sprawdzać, czy wyświetlany jest prawidłowy wynik.

Kotlin


private const val CALC_PACKAGE = "com.myexample.calc"

fun testTwoPlusThreeEqualsFive() {
  // Enter an equation: 2 + 3 = ?
  device.findObject(By.res(CALC_PACKAGE, "two")).click()
  device.findObject(By.res(CALC_PACKAGE, "plus")).click()
  device.findObject(By.res(CALC_PACKAGE, "three")).click()
  device.findObject(By.res(CALC_PACKAGE, "equals")).click()

  // Verify the result = 5
  val result: UiObject2 = device.findObject(By.res(CALC_PACKAGE, "result"))
  assertEquals("5", result.text)
}

Java


private static final String CALC_PACKAGE = "com.myexample.calc";

public void testTwoPlusThreeEqualsFive() {
  // Enter an equation: 2 + 3 = ?
  device.findObject(By.res(CALC_PACKAGE, "two")).click();
  device.findObject(By.res(CALC_PACKAGE, "plus")).click();
  device.findObject(By.res(CALC_PACKAGE, "three")).click();
  device.findObject(By.res(CALC_PACKAGE, "equals")).click();

  // Verify the result = 5
  UiObject2 result = device.findObject(By.res(CALC_PACKAGE, "result"));
  assertEquals("5", result.getText());
}

Uruchamiaj testy Automatora UI na urządzeniu lub w emulatorze

Testy Automatora interfejsu możesz uruchamiać w Android Studio lub z poziomu wiersza poleceń. Pamiętaj, aby określić AndroidJUnitRunner jako domyślną aplikację uruchamiającą instrument w projekcie.

Więcej przykładów

Interakcja z interfejsem systemu

Automator UI może wchodzić w interakcje ze wszystkim, co znajduje się na ekranie, w tym z elementami systemu poza aplikacją, jak pokazano w tych fragmentach kodu:

Kotlin


// Opens the System Settings.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
device.executeShellCommand("am start -a android.settings.SETTINGS")

Java


// Opens the System Settings.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
device.executeShellCommand("am start -a android.settings.SETTINGS");

Kotlin


// Opens the notification shade.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
device.openNotification()

Java


// Opens the notification shade.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
device.openNotification();

Kotlin


// Opens the Quick Settings shade.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
device.openQuickSettings()

Java


// Opens the Quick Settings shade.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
device.openQuickSettings();

Kotlin


// Get the system clock.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
UiObject2 clock = device.findObject(By.res("com.android.systemui:id/clock"))
print(clock.getText())

Java


// Get the system clock.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
UiObject2 clock = device.findObject(By.res("com.android.systemui:id/clock"));
print(clock.getText());

Poczekaj na przeniesienie

Wyłącz zakłócenia
Rysunek 1. Automator UI wyłącza tryb Nie przeszkadzać na urządzeniu testowym.

Przejścia ekranu mogą trochę potrwać, a przewidywanie ich czasu trwania jest mało miarodajne, dlatego Automator UI powinien czekać po wykonaniu operacji. Automator UI udostępnia wiele metod, które pozwalają to zrobić:

Ten fragment kodu pokazuje, jak za pomocą narzędzia UI Automator wyłączyć tryb Nie przeszkadzać w ustawieniach systemu przy użyciu metody performActionAndWait(), która oczekuje na przeniesienie:

Kotlin


@Test
@SdkSuppress(minSdkVersion = 21)
@Throws(Exception::class)
fun turnOffDoNotDisturb() {
    device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
    device.performActionAndWait({
        try {
            device.executeShellCommand("am start -a android.settings.SETTINGS")
        } catch (e: IOException) {
            throw RuntimeException(e)
        }
    }, Until.newWindow(), 1000)
    // Check system settings has been opened.
    Assert.assertTrue(device.hasObject(By.pkg("com.android.settings")))

    // Scroll the settings to the top and find Notifications button
    var scrollableObj: UiObject2 = device.findObject(By.scrollable(true))
    scrollableObj.scrollUntil(Direction.UP, Until.scrollFinished(Direction.UP))
    val notificationsButton = scrollableObj.findObject(By.text("Notifications"))

    // Click the Notifications button and wait until a new window is opened.
    device.performActionAndWait({ notificationsButton.click() }, Until.newWindow(), 1000)
    scrollableObj = device.findObject(By.scrollable(true))
    // Scroll down until it finds a Do Not Disturb button.
    val doNotDisturb = scrollableObj.scrollUntil(
        Direction.DOWN,
        Until.findObject(By.textContains("Do Not Disturb"))
    )
    device.performActionAndWait({ doNotDisturb.click() }, Until.newWindow(), 1000)
    // Turn off the Do Not Disturb.
    val turnOnDoNotDisturb = device.findObject(By.text("Turn on now"))
    turnOnDoNotDisturb?.click()
    Assert.assertTrue(device.wait(Until.hasObject(By.text("Turn off now")), 1000))
}

Java


@Test
@SdkSuppress(minSdkVersion = 21)
public void turnOffDoNotDisturb() throws Exception{
    device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
    device.performActionAndWait(() -> {
        try {
            device.executeShellCommand("am start -a android.settings.SETTINGS");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }, Until.newWindow(), 1000);
    // Check system settings has been opened.
    assertTrue(device.hasObject(By.pkg("com.android.settings")));

    // Scroll the settings to the top and find Notifications button
    UiObject2 scrollableObj = device.findObject(By.scrollable(true));
    scrollableObj.scrollUntil(Direction.UP, Until.scrollFinished(Direction.UP));
    UiObject2 notificationsButton = scrollableObj.findObject(By.text("Notifications"));

    // Click the Notifications button and wait until a new window is opened.
    device.performActionAndWait(() -> notificationsButton.click(), Until.newWindow(), 1000);
    scrollableObj = device.findObject(By.scrollable(true));
    // Scroll down until it finds a Do Not Disturb button.
    UiObject2 doNotDisturb = scrollableObj.scrollUntil(Direction.DOWN,
            Until.findObject(By.textContains("Do Not Disturb")));
    device.performActionAndWait(()-> doNotDisturb.click(), Until.newWindow(), 1000);
    // Turn off the Do Not Disturb.
    UiObject2 turnOnDoNotDisturb = device.findObject(By.text("Turn on now"));
    if(turnOnDoNotDisturb != null) {
        turnOnDoNotDisturb.click();
    }
    assertTrue(device.wait(Until.hasObject(By.text("Turn off now")), 1000));
}

Dodatkowe materiały

Więcej informacji o korzystaniu z Automatora UI w testach Androida znajdziesz w tych materiałach.

Dokumentacja źródłowa:

Próbki

  • BasicSample: przykład narzędzia Automator podstawowego interfejsu użytkownika.