Добавьте тесты Espresso и UiAutomator в приложение Surface Duo

Espresso и UiAutomator — это платформы тестирования, предоставляемые библиотеками AndroidX. Espresso используется для поиска элементов пользовательского интерфейса в приложении и взаимодействия с ними, а UiAutomator предоставляет функции тестирования разных приложений и обеспечивает возможность доступа к датчикам устройств.

Чтобы узнать больше об этих платформах тестирования, ознакомьтесь с этими ресурсами:

В проекте Android Studio вы будете писать эти тесты пользовательского интерфейса в разделе androidTest. Имя файла теста по умолчанию — ExampleInstrumentedTest. Не забудьте отключить анимацию на своем устройстве, прежде чем выполнять тестирование.

Зависимости

Добавьте следующие зависимости в файл build.gradle приложения.

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

dependencies {
    testImplementation "junit:junit:4.13"
    androidTestImplementation "androidx.test.ext:junit:1.1.1"
    androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0"
    androidTestImplementation "androidx.test:runner:1.2.0"
    androidTestImplementation "androidx.test:rules:1.2.0"
    androidTestImplementation "androidx.test.uiautomator:uiautomator:2.2.0"
}

Если тестирование осуществляется с помощью WebView, в раздел зависимостей также нужно добавить androidTestImplementation "androidx.test.espresso:espresso-web:3.2.0".

Примечание

Если используется отдельный файл dependencies.gradle, см. репозитории с примерами приложений, в которых показано, как добавлять требуемые зависимости.

Создание правил для тестов

Вы можете добавить в тесты правила JUnit, чтобы указать дополнительные сведения о последующих тестах. Одно из самых распространенных правил — определение основного действия для тестов, к которому будут применены тесты, как показано ниже.

@RunWith(AndroidJUnit4::class)
class PhotoEditorUITest {
    @get:Rule
    val activityRule = ActivityTestRule(MainActivity::class.java)
}

Написание тестов пользовательского интерфейса с двумя экранами

Основы

Используйте класс UiDevice, предоставляемый UiAutomator, для поиска устройства и изменения его конфигураций растягивания и поворота, а затем используйте Espresso для проверки того, что элементы пользовательского интерфейса работают должным образом.

Как показано в следующем примере, метод swipe можно использовать для имитации растягивания и сжимания. Чтобы сделать тесты максимально надежными, попытайтесь сгруппировать тесты, которые используют одинаковую конфигурацию, чтобы не создавать несколько соответствующих запросов на растягивание и сжимание.

@Test
fun testSpan() {
    val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

    // Span the app (from the left side)
    device.swipe(675, 1780, 1350, 900, 400)

    // Test that UI element appears
    onView(withId(R.id.yourElement)).check(matches(isDisplayed()))

    // Unspan the app (to the left side)
    // device.swipe(2109, 1780, 675, 900, 200)

    // Test that UI element has disappeared
    // onView(withId(R.id.yourElement)).check(matches(not(isDisplayed())))
}

К другим полезным функциям UiAutomator относятся setOrientationNatural, unfreezeRotation и pressHome. Если требуется протестировать функции разных приложений, можно также использовать UiAutomator для запуска других приложений.

Вспомогательные функции

Для имитации растягивания можно использовать следующие базовые вспомогательные функции.

companion object {
    // testing device
    val device: UiDevice = UiDevice.getInstance(getInstrumentation())

    // Swipe constants
    const val leftX: Int = 675          // middle of left screen
    const val rightX: Int = 2109        // middle of right screen
    const val middleX: Int = 1350       // hinge area
    const val bottomY: Int = 1780       // bottom of screen
    const val middleY: Int = 900        // middle of screen
    const val spanSteps: Int = 400      // spanning swipe
    const val unspanSteps: Int = 200    // unspanning swipe
    const val switchSteps: Int = 100    // swipe to switch from one screen to the other
    const val closeSteps: Int = 50      // swipe to close app
}

private fun spanFromLeft() {
    device.swipe(leftX, bottomY, middleX, middleY, spanSteps)
}

private fun unspanToLeft() {
    device.swipe(rightX, bottomY, leftX, middleY, unspanSteps)
}

private fun spanFromRight() {
    device.swipe(rightX, bottomY, middleX, middleY, spanSteps)
}

private fun unspanToRight() {
    device.swipe(leftX, bottomY, rightX, middleY, unspanSteps)
}

private fun switchToLeft() {
    device.swipe(rightX, bottomY, leftX, middleY, switchSteps)
}

private fun switchToRight() {
    device.swipe(leftX, bottomY, rightX, middleY, switchSteps)
}

private fun closeLeft() {
    device.swipe(leftX, bottomY, leftX, middleY, closeSteps)
}

private fun closeRight() {
    device.swipe(rightX, bottomY, rightX, middleY, closeSteps)
}

Чтобы проверить, растянуто ли приложение, определите правило, которое подключается к основному действию, и используйте его для замены в этой функции:

private fun isSpanned(): Boolean {
    onIdle() // wait until layout changes have been fully processed before checking
    return ScreenHelper.isDualMode(activityRule.activity)
}

Чтобы убедиться, что все вспомогательные функции работают должным образом, добавьте import org.hamcrest.CoreMatchers.`is` as iz в инструкции import, а затем выполните следующий тест.

/**
 * Runs helper functions and checks that they work as expected
 *
 * @precondition device in portrait mode, no other applications are open
 * (so app by default opens on left screen)
 */
@Test
fun testSpanningHelperFunctions() {
    spanFromLeft()
    assertThat(isSpanned(), iz(true))

    unspanToRight()
    assertThat(isSpanned(), iz(false))

    spanFromRight()
    assertThat(isSpanned(), iz(true))

    unspanToLeft()
    assertThat(isSpanned(), iz(false))

    switchToRight()
    switchToLeft()
    closeLeft()
}

Советы по устранению неполадок

Если тест testSpanningHelperFunctions завершается сбоем или возникают другие проблемы, связанные с тестированием:

  • Измените константы шага. Для правильной обработки некоторых жестов требуется, чтобы они были достаточно медленными. 100 шагов выполняются примерно за 0,5 секунды.
  • Измените константы x и y, представляющие значения пикселей на экране. Каждый экран имеет размер 1350 x 1800 пикселей, а зазор шарнира составляет 84 пикселя в ширину (размеры Surface Duo).
  • Добавьте IdlingResources в тесты, которые загружают данные или выполняют другие асинхронные операции с возможным влиянием на тесты пользовательского интерфейса.

Сводка

Тестирование пользовательского интерфейса для приложений Surface Duo можно выполнить, используя платформы тестирования Espresso и UiAutomator вместе. В большинстве случаев метод прокрутки, доступный в UiAutomator, — это все, что нужно для имитации событий двойного экрана. Затем вы можете как обычно использовать Espresso для взаимодействия с элементами пользовательского интерфейса в приложении Surface Duo.

Примеры тестирования пользовательского интерфейса в приложениях Surface Duo см. в следующих ресурсах: