Ajouter des tests Espresso et UiAutomator à votre application Surface Duo

Espresso et UiAutomator sont des frameworks de test fournis par les bibliothèques AndroidX. Espresso permet de trouver les éléments d’interface utilisateur d’une application et d’interagir avec eux, tandis que UiAutomator fournit des fonctionnalités de test entre applications et un accès aux capteurs de l’appareil.

Pour en savoir plus sur ces frameworks de test, consultez les ressources suivantes :

Dans votre projet Android Studio, écrivez ces tests d’interface utilisateur dans la section androidTest, où le fichier de test par défaut est nommé ExampleInstrumentedTest. N’oubliez pas de désactiver les animations sur votre appareil avant d’exécuter vos tests d’interface utilisateur.

Dépendances

Ajoutez les dépendances suivantes au fichier build.gradle de votre application :

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

Si vous effectuez vos tests avec un WebView, vous devez ajouter androidTestImplementation "androidx.test.espresso:espresso-web:3.2.0" à la section dependencies.

Notes

Si vous utilisez un fichier dependencies.gradle distinct, consultez ce dépôt d’exemples d’application pour obtenir des exemples sur la façon d’ajouter les dépendances nécessaires.

Créer des règles pour les tests

Vous pouvez ajouter des règles JUnit à vos tests pour spécifier des informations supplémentaires sur les tests ultérieurs. Une règle couramment utilisée consiste à définir une activité principale à laquelle sont appliqués les tests, comme indiqué ci-dessous :

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

Écrire des tests d’interface utilisateur double écran

Notions de base

Utilisez la classe UiDevice fournie par UiAutomator pour trouver votre appareil et changer ses configurations de répartition/rotation d’écran, puis utilisez Espresso pour vérifier que les éléments d’interface utilisateur se comportent comme prévu.

Comme le montre l’exemple ci-dessous, la méthode swipe peut être utilisée pour simuler la répartition sur deux écrans et le retour à un écran. Pour que vos tests soient les plus fiables possible, essayez de regrouper ceux qui nécessitent la même configuration afin de ne pas avoir à effectuer plusieurs demandes de répartition sur deux écrans et de retour à un écran.

@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 comprend d’autres fonctions utiles, comme setOrientationNatural, unfreezeRotation et pressHome. Si vous souhaitez tester les fonctionnalités entre applications, vous pouvez également utiliser UiAutomator pour lancer d’autres applications.

Fonctions d’assistance

Vous pouvez utiliser ces fonctions d’assistance de base pour simuler un comportement de répartition :

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

Pour tester si une application est répartie sur deux écrans, définissez une règle qui se connecte à l’activité principale et utilisez-la pour remplacer dans cette fonction :

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

Pour vérifier que toutes les fonctions d’assistance fonctionnent comme prévu, ajoutez import org.hamcrest.CoreMatchers.`is` as iz à vos instructions d’importation, puis exécutez le test suivant :

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

Conseils de dépannage

Si le test testSpanningHelperFunctions échoue ou si vous rencontrez d’autres problèmes liés aux tests :

  • Ajustez les constantes d’étape. Certains mouvements doivent être suffisamment lents pour garantir un bon traitement. 100 étapes prennent environ 0.5 seconde.
  • Modifiez les constantes x et y qui représentent des valeurs en pixels à l’écran. Chaque écran mesure 1350 x 1800 px, et la largeur de la charnière est de 84 px (Dimensions de Surface Duo).
  • Ajoutez IdlingResources aux tests qui chargent des données ou exécutent d’autres opérations asynchrones susceptibles d’affecter les tests d’interface utilisateur.

Résumé

Pour tester l’interface utilisateur d’applications Surface Duo, vous pouvez combiner les frameworks de test Espresso et UiAutomator. Dans la plupart des cas, la méthode swipe de UiAutomator suffit pour simuler des événements double écran. Vous pouvez ensuite utiliser Espresso normalement pour interagir avec les éléments d’interface utilisateur dans votre application Surface Duo.

Pour obtenir des exemples de test d’interface utilisateur sur des applications Surface Duo, consultez les ressources suivantes :