web-dev-qa-db-fra.com

Android Marshmallow: Testez les autorisations avec Espresso?

Le nouveau schéma d'autorisations introduit par Android Marshmallow requiert la vérification d'autorisations spécifiques lors de l'exécution, ce qui implique la nécessité de fournir des flux différents selon que l'utilisateur refuse ou autorise l'accès.

Comme nous utilisons Espresso pour exécuter des tests d’interface utilisateur automatisés sur notre application, comment pouvons-nous nous moquer ou mettre à jour l’état des autorisations afin de tester différents scénarios?

53
argenkiwi

Avec la nouvelle version de Android Testing Support Library 1.0 , il existe un GrantPermissionRule que vous pouvez utiliser dans vos tests pour accorder une autorisation avant de commencer les tests.

@Rule public GrantPermissionRule permissionRule = GrantPermissionRule.grant(Android.Manifest.permission.ACCESS_FINE_LOCATION);
63
Niklas

La réponse acceptée ne teste pas réellement la boîte de dialogue des autorisations; il le contourne simplement. Ainsi, si la boîte de dialogue des autorisations échoue pour une raison quelconque, votre test donnera un faux vert. Je vous encourage à cliquer sur le bouton "donner des autorisations" pour tester le comportement de l'application dans son ensemble.

Regardez cette solution:

public static void allowPermissionsIfNeeded(String permissionNeeded) {
    try { 
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !hasNeededPermission(permissionNeeded)) {
        sleep(PERMISSIONS_DIALOG_DELAY);
        UiDevice device = UiDevice.getInstance(getInstrumentation());
        UiObject allowPermissions = device.findObject(new UiSelector()
          .clickable(true) 
          .checkable(false) 
          .index(GRANT_BUTTON_INDEX));
        if (allowPermissions.exists()) {
          allowPermissions.click();
        } 
      } 
    } catch (UiObjectNotFoundException e) {
      System.out.println("There is no permissions dialog to interact with");
    } 
  } 

Retrouvez la classe entière ici: https://Gist.github.com/rocboronat/65b1187a9fca9eabfebbb1212d818a3c4

Soit dit en passant, cette réponse étant populaire, nous avons ajouté PermissionGranter à Barista, notre outil situé au-dessus d’Expresso et de UiAutomator pour rendre les tests instrumentaux écologiques: https://github.com/SchibstedSpain/Barista vérifiez-le, car nous le maintiendrons publication par publication.

33
Roc Boronat

Essayez avec cette méthode statique lorsque votre téléphone est en langue anglaise:

private static void allowPermissionsIfNeeded() {
    if (Build.VERSION.SDK_INT >= 23) {
        UiDevice device = UiDevice.getInstance(getInstrumentation());
        UiObject allowPermissions = device.findObject(new UiSelector().text("Allow"));
        if (allowPermissions.exists()) {
            try {
                allowPermissions.click();
            } catch (UiObjectNotFoundException e) {
                Timber.e(e, "There is no permissions dialog to interact with ");
            }
        }
    }
}

Je l'ai trouvé ici

29
riwnodennyk

Vous pouvez accorder des autorisations avant que le test soit exécuté avec quelque chose comme:

@Before
public void grantPhonePermission() {
    // In M+, trying to call a number will trigger a runtime dialog. Make sure
    // the permission is granted before running this test.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        getInstrumentation().getUiAutomation().executeShellCommand(
                "pm grant " + getTargetContext().getPackageName()
                        + " Android.permission.CALL_PHONE");
    }
}

Mais vous ne pouvez pas révoquer. Si vous essayez pm reset-permissions ou pm revoke..., le processus est tué.

19
Jose Alcérreca

En fait, il y a 2 façons de le faire que je connaisse jusqu'à présent:

  1. Accordez l'autorisation à l'aide de la commande adb avant le début du test ( documentation ):

adb Shell pm grant "com.your.package" Android.permission.your_permission

  1. Vous pouvez cliquer sur le dialogue d'autorisation et définir l'autorisation à l'aide de UIAutomator ( documentation ). Si vos tests sont écrits avec Espresso pour Android, vous pouvez facilement combiner les étapes Espresso et UIAutomator en un seul test.
11
denys

Vous pouvez y parvenir facilement en accordant une autorisation avant de commencer le test. Par exemple, si vous êtes censé utiliser l'appareil photo pendant l'exécution du test, vous pouvez accorder l'autorisation comme suit

@Before
public void grantPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        getInstrumentation().getUiAutomation().executeShellCommand(
                "pm grant " + getTargetContext().getPackageName()
                        + " Android.permission.CAMERA");
    }
}
7

MISE À JOUR ESPRESSO

Cette seule ligne de code accorde toutes les autorisations listées comme paramètre dans la méthode des subventions avec effet immédiat. En d'autres termes, l'application sera traité comme si les autorisations étaient déjà accordées - pas plus dialogues

@Rule @JvmField
val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(Android.Manifest.permission.ACCESS_FINE_LOCATION)

et gradé

dependencies {
  ...
  testImplementation "junit:junit:4.12"
  androidTestImplementation "com.Android.support.test:runner:1.0.0"
  androidTestImplementation "com.Android.support.test.espresso:espresso-core:3.0.0"
  ...
}

référence: https://www.kotlindevelopment.com/runtime-permissions-espresso-done-right/

3
murt

Merci @niklas pour la solution. Si quelqu'un cherche à accorder plusieurs autorisations en Java:

 @Rule
public GrantPermissionRule permissionRule = GrantPermissionRule.grant(Android.Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.CAMERA);
0
learner

Je sais qu'une réponse a été acceptée, cependant, au lieu de la déclaration if qui a été suggérée maintes et maintes fois, une autre approche plus élégante consisterait à effectuer les opérations suivantes dans le test réel souhaité pour une version spécifique du système d'exploitation:

@Test
fun yourTestFunction() {
    Assume.assumeTrue(Build.VERSION.SDK_INT >= 23)
    // the remaining assertions...
}

Si la fonction assumeTrue est appelée avec une expression évaluée à false, le test s’arrête et est ignoré, ce que je suppose comme étant ce que vous voulez si le test est exécuté sur un périphérique pré-SDK 23.

0
Edison Spencer

Il y a GrantPermissionRule dans Android Testing Support Library , que vous pouvez utiliser dans vos tests pour accorder une autorisation avant de commencer des tests.

@Rule public GrantPermissionRule permissionRule = GrantPermissionRule.grant(Android.Manifest.permission.CAMERA, Android.Manifest.permission.ACCESS_FINE_LOCATION);
0
NSK

J'ai implémenté une solution qui exploite les classes wrapper, redéfinit et construit les variantes de configuration. La solution est assez longue à expliquer et se trouve ici: https://github.com/ahasbini/AndroidTestMockPermissionUtils .

Il n'est pas encore emballé dans un sdk mais l'idée principale est de remplacer les fonctionnalités de ContextWrapper.checkSelfPermission et ActivityCompat.requestPermissions à manipuler et à renvoyer les résultats fictifs capturant l'application dans les différents scénarios à tester, comme par exemple: l'autorisation a été refusée avec la permission accordée. Ce scénario se produira même si l'application avait l'autorisation depuis le début, mais l'idée est qu'il a été trompé par les résultats simulés de l'implémentation prépondérante.

De plus, l'implémentation a une classe TestRule appelée PermissionRule qui peut être utilisée dans les classes de test pour simuler facilement toutes les conditions permettant de tester les autorisations de manière transparente. Des affirmations peuvent également être faites, comme s’assurer que l’application a appelé requestPermissions() par exemple.

0
ahasbini