¿Cuál es la mejor forma / herramienta para probar las pruebas de la aplicación Android M para obtener el permiso del dispositivo?

Gracias 4 A2A,

Hay varias herramientas disponibles para probar la aplicación de Android, algunas de ellas son gratuitas, otras son bastante caras. Recomiendo usar debajo de uno.

  • UI Automator

Configuración de UiAutomator

UiAutomator viene con el repositorio local de Maven que es parte del SDK de Android, por lo que simplemente puede agregar esta línea al build.gradle file:

dependencias {
// otras dependencias

androidTestCompile ‘com.android.support.test.uiautomator: uiautomator-v18: 2.1.2’
}

Sin embargo, si su nivel mínimo de SDK se establece en un valor inferior a 18, la compilación fallará, produciendo algo como esto:

Error: Falló la ejecución de la tarea ‘: aplicación: processDebugAndroidTestManifest’.
> java.lang.RuntimeException: falló la fusión de manifiesto: uses-sdk: minSdkVersion 16 no puede ser menor que la versión 18 declarada en la biblioteca [com.android.support.test.uiautomator: uiautomator-v18: 2.1.2] / /app/build/intermediates/exploded-aar/com.android.support.test.uiautomator/uiautomator-v18/2.1.2/AndroidManifest.xml

Sugerencia: use tools:overrideLibrary = “android.support.test.uiautomator.v18” para forzar el uso

Como sugiere el mensaje de error, esto se puede solucionar agregando las tools:overrideLibrary elemento tools:overrideLibrary al Manifiesto, pero el truco es que debería terminar dentro de un archivo Manifiesto en el directorio androidTest, así que solo cree uno con el siguiente contenido:

<manifiesto
package = “me.egorand.contactssync”
xmlns: tools = “http://schemas.android.com/tools”>

Ahora la compilación se ejecuta normalmente y estamos listos para comenzar.

Caso de prueba 1 : se muestra el cuadro de diálogo de permiso de solicitud

Primero, escriba una prueba que simplemente verifique que el diálogo de solicitud se muestre tan pronto como abramos la aplicación. Recuerde, no podemos hacer esto con Espresso, ya que no tiene acceso a ninguna interfaz de usuario que esté fuera de nuestro paquete. Por lo tanto, usaremos UiAutomator y crearemos un método auxiliar que se vea así:

public static void afirmarViewWithTextIsVisible (dispositivo UiDevice, texto de cadena) {
UiObject allowButton = device.findObject (nuevo UiSelector (). Text (text));
if (! allowButton.exists ()) {
lanzar nuevo AssertionError (“¡Ver con texto no encontrado!”);
}
}

UiDevice es una abstracción que UiAutomator utiliza para interactuar con el dispositivo de prueba: además del método findObject (), que nos ayuda a obtener los componentes de la interfaz de usuario en la pantalla, tiene varios métodos como pressBack (), pressHome ( ) y otros. UiSelector es una clase que nos ayuda a crear una consulta que podemos pasar a findObject () para localizar el componente de la interfaz de usuario que nos interesa.

Al final de la prueba, también queremos descartar el cuadro de diálogo de permisos para evitar tenerlo en la pantalla cuando comience la próxima prueba. Para denegar el permiso, utilizaremos el siguiente método auxiliar:

public static void denyCurrentPermission (dispositivo UiDevice) lanza UiObjectNotFoundException {
UiObject denyButton = device.findObject (nuevo UiSelector (). Text (TEXT_DENY));
denyButton.click ();
}

Este método utiliza el mismo enfoque para ubicar el botón Denegar, y luego invoca click () para interactuar con él. Tenga en cuenta que el método arrojará una UiObjectNotFoundException si no puede encontrar el botón en la pantalla.

Con estos métodos, podremos crear el siguiente método de prueba:

@Prueba
public void a_shouldDisplayPermissionRequestDialogAtStartup () genera una excepción {
ClaimViewWithTextIsVisible (dispositivo, “PERMITIR”);
ClaimViewWithTextIsVisible (dispositivo, “DENY”);

// limpieza para la próxima prueba
denyCurrentPermission (dispositivo);
}

Tenga en cuenta que el nombre del método comienza con a. Estoy haciendo esto aquí para controlar el orden en que el corredor de prueba invocará los métodos de prueba. Por cierto, no esperes que JUnit resuelva esto automáticamente, si necesitas un cierto orden para tus métodos de prueba, agrega la siguiente anotación a la clase de prueba:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)

Me sentía reacio a imponer el estricto orden de las pruebas, ya que creo que siempre es mejor si las pruebas son independientes. Pero para tener un conjunto de pruebas independientes, necesitamos implementar la limpieza correctamente, llevando el estado de la aplicación al inicio después de cada prueba. En este ejemplo en particular, esto significaría que debemos asegurarnos de que se revoquen todos los permisos antes de que comience cada prueba. El problema con este enfoque es que el proceso de solicitud se anula cuando revoca un permiso. El corredor de prueba no espera este tipo de comportamiento, por lo tanto, las pruebas no se ejecutarán hasta su finalización. Por lo tanto, tendremos que recurrir al estricto orden en este conjunto de pruebas.

Para pasar esta prueba, haremos lo siguiente dentro de la Actividad:

@Anular
nulo protegido en Resume () {
super.onResume ();

int permissionStatus = ContextCompat.checkSelfPermission (this, Manifest.permission.READ_CONTACTS);
if (permissionStatus == PackageManager.PERMISSION_GRANTED) {
loadContacts ();
} else if (! isPermissionAlreadyDenied) {
ActivityCompat.requestPermissions (esto, nueva Cadena [] {Manifest.permission.READ_CONTACTS},
REQ_CODE_PERMISSIONS_READ_CONTACTS);
}
}

Si el permiso ya está otorgado, simplemente cargaremos los contactos, de lo contrario, solicitaremos el permiso. También mantendremos un indicador llamado isPermissionAlreadyDenied para evitar solicitar el permiso inmediatamente después de hacer clic en Denegar, ya que el cierre del cuadro de diálogo de permisos activará OnResume ().

Caso de prueba B : se muestra una breve justificación si se deniega el permiso

Deneguemos ahora el permiso y verifiquemos que se muestra la justificación:

@Prueba
public void b_shouldDisplayShortRationaleIfPermissionWasDenied () lanza Exception {
denyCurrentPermission (dispositivo);

onView (withText (R.string.permission_denied_rationale_short)). check (coincide (isDisplayed ()));
onView (withText (R.string.grant_permission)). check (coincide (isDisplayed ()));
}

Tenga en cuenta que tan pronto como volvamos a interactuar con nuestra propia interfaz de usuario, podemos continuar usando la API de Espresso de forma segura.

El siguiente fragmento dentro de la clase Actividad debería pasar esta prueba:

@Anular
public void onRequestPermissionsResult (int requestCode, @NonNull String [] permisos,
@NonNull int [] grantResults) {
if (requestCode == REQ_CODE_PERMISSIONS_READ_CONTACTS && grantResults.length> 0) {
int grantResult = grantResults [0];
if (grantResult == PackageManager.PERMISSION_GRANTED) {
loadContacts ();
} más {
isPermissionAlreadyDenied = true;
if (ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.READ_CONTACTS)) {
permissionDeniedRationaleView.setText (R.string.permission_denied_rationale_short);
}
permissionDeniedView.setVisibility (View.VISIBLE);
}
} más {
super.onRequestPermissionsResult (requestCode, permissions, grantResults);
}
}

Caso de prueba C : se muestra una justificación larga si el permiso se deniega permanentemente

Por “denegado permanentemente” me refiero a que el usuario ha marcado la casilla de verificación Nunca preguntar de nuevo, lo que nos impide mostrar cuadros de diálogo de permisos en el futuro. La siguiente prueba verifica que estamos mostrando una justificación más larga que contiene las instrucciones sobre cómo otorgar el permiso desde la pantalla Configuración:

@Prueba
public void c_shouldDisplayLongRationaleIfPermissionWasDeniedPermanently () genera una excepción {
denyCurrentPermissionPermanently (dispositivo);

onView (withText (R.string.permission_denied_rationale_long)). check (coincide (isDisplayed ()));
onView (withText (R.string.grant_permission)). check (coincide (isDisplayed ()));

// otorgará el permiso para la próxima prueba
onView (withText (R.string.grant_permission)). perform (click ());
permisos abiertos (dispositivo);
grantPermission (dispositivo, “Contactos”);
}

Estamos utilizando otro método auxiliar llamado denyCurrentPermissionPermanently:

public static void denyCurrentPermissionPermanently (dispositivo UiDevice) lanza UiObjectNotFoundException {
UiObject neverAskAgainCheckbox = device.findObject (nuevo UiSelector (). Text (TEXT_NEVER_ASK_AGAIN));
neverAskAgainCheckbox.click ();
denyCurrentPermission (dispositivo);
}

Marcará la marca de verificación antes de denegar el permiso.

Además, incluimos un código de limpieza que preparará la configuración para nuestra próxima prueba. Necesitamos navegar a la pantalla de Configuración, luego abrir la página de Permisos y otorgar el permiso alternando el interruptor. La lógica de abrir la pantalla de Configuración debe implementarse en el código de Actividad, por lo que el código de prueba puede tocar el botón de permiso de Concesión y luego usar los siguientes métodos:

public static void openPermissions (dispositivo UiDevice) lanza UiObjectNotFoundException {
Permisos de UiObject = device.findObject (new UiSelector (). Text (TEXT_PERMISSIONS));
permisos.click ();
}
public static void grantPermission (dispositivo UiDevice, String permissionTitle) arroja UiObjectNotFoundException {
UiObject permissionEntry = device.findObject (nuevo UiSelector (). Text (permissionTitle));
permissionEntry.click ();
}

Dentro del código de actividad, actualizaremos el código de RequestPermissionsResult() con lo siguiente:


if (ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.READ_CONTACTS)) {
permissionDeniedRationaleView.setText (R.string.permission_denied_rationale_short);
} más {
permissionDeniedRationaleView.setText (R.string.permission_denied_rationale_long);
}

Desafortunadamente, la API de Android no proporciona una forma clara de identificar el hecho de que nunca se volvió a preguntar, por lo tanto, tendremos que confiar en el comportamiento de shouldShowRequestPermissionRationale (), que devuelve falso en este caso.

El código del controlador de clics para el botón de permiso de concesión se ve así:

public void onGrantPermission (Ver vista) {
if (ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.READ_CONTACTS)) {
ActivityCompat.requestPermissions (esto, nueva Cadena [] {Manifest.permission.READ_CONTACTS},
REQ_CODE_PERMISSIONS_READ_CONTACTS);
} más {
ir a la configuración();
}
}

goToSettings privado vacío () {
Uri uri = Uri.fromParts (“paquete”, getPackageName (), nulo);
Intent settingsIntent = Nuevo Intent (Settings.ACTION_APPLICATION_DETAILS_SETTINGS, uri);
settingsIntent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity (settingsIntent);
}

Con todo listo, pasemos al último caso de prueba.

Caso de prueba D : debe cargar contactos si se otorga el permiso

Este es bastante sencillo:

@Prueba
public void d_shouldLoadContactsIfPermissionWasGranted () produce una excepción {
para (Contacto de contacto: TEST_CONTACTS) {
onView (withText (contact.name)). check (coincide (isDisplayed ()));
onView (withText (contact.phoneNumber)). check (coincide (isDisplayed ()));
}
}

Como hemos otorgado previamente el permiso, el código para cargar los contactos debería activarse, y se completará la lista.

¡Gracias!

Fuente: Desarrolladores de Android, Blog de un desarrollador de Android