En esta publicación, aprenderá cómo escribir pruebas de UI con el marco de prueba de Espresso y automatizar su flujo de trabajo de prueba, en lugar de usar el proceso manual tedioso y altamente propenso a errores.
Espresso es un marco de prueba para escribir pruebas de interfaz de usuario en Android. Según los documentos oficiales, usted puede:
Use Espresso para escribir pruebas de IU de Android concisas, hermosas y confiables.
Uno de los problemas con las pruebas manuales es que puede llevar mucho tiempo y ser tedioso de realizar. Por ejemplo, para probar una pantalla de inicio de sesión (manualmente) en una aplicación de Android, deberá hacer lo siguiente:
usernameEditText
y passwordEditText
son visibles. ¡En lugar de pasar todo este tiempo probando manualmente nuestra aplicación, sería mejor dedicar más tiempo a escribir un código que haga que nuestra aplicación se destaque del resto! Y, aunque las pruebas manuales son tediosas y bastante lentas, siguen siendo propensas a errores y es posible que se pierda algunos casos de esquina..
Algunas de las ventajas de las pruebas automatizadas incluyen las siguientes:
En este tutorial, aprenderemos sobre Espresso integrándolo en un proyecto de Android Studio. Escribiremos pruebas de UI para una pantalla de inicio de sesión y una RecyclerView
, y aprenderemos sobre los intentos de prueba.
La calidad no es un acto, es un hábito. - Pablo Picasso
Para poder seguir este tutorial, necesitarás:
Puede encontrar un proyecto de muestra (en Kotlin) para este tutorial en nuestro repositorio de GitHub para que pueda seguirlo fácilmente..
Encienda su Android Studio 3 y cree un nuevo proyecto con una actividad vacía llamada Actividad principal
. Asegúrese de comprobar Incluye soporte de Kotlin..
AndroidJUnitRunner
Después de crear un nuevo proyecto, asegúrese de agregar las siguientes dependencias de la biblioteca de soporte de pruebas de Android en su construir.gradle (aunque Android Studio ya los ha incluido para nosotros). En este tutorial, estamos utilizando la última versión de la biblioteca Espresso 3.0.2 (en el momento de escribir este artículo).
android // ... defaultConfig // ... testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" // ... dependencies // ... androidTestImplementation 'com.android.support.test.espresso: espresso-core: 3.0. 2 'androidTestImplementation' com.android.support.test: runner: 1.0.2 'androidTestImplementation' com.android.support.test: rules: 1.0.2 '
También incluimos el corredor de instrumentación. AndroidJUnitRunner
:
Un Instrumentación
que ejecuta las pruebas JUnit3 y JUnit4 contra un paquete de Android (aplicación).
Tenga en cuenta que Instrumentación
es simplemente una clase base para implementar código de instrumentación de aplicación.
La sincronización de Espresso, que no sabe cómo esperar a que termine una animación, puede hacer que algunas pruebas fallen, si permite la animación en su dispositivo de prueba. Para desactivar la animación en su dispositivo de prueba, vaya a Ajustes > Opciones de desarrollador y desactive todas las siguientes opciones en la sección "Dibujo":
Primero, comenzamos a probar una pantalla de inicio de sesión. Así es como comienza el flujo de inicio de sesión: el usuario inicia la aplicación y la primera pantalla que se muestra contiene una sola Iniciar sesión botón. Cuando eso Iniciar sesión Se hace clic en el botón, se abre el Iniciar sesiónActividad
pantalla. Esta pantalla contiene solo dos Editar texto
s (los campos de nombre de usuario y contraseña) y un Enviar botón.
Esto es lo que nuestro Actividad principal
el diseño se ve como
Esto es lo que nuestro Iniciar sesiónActividad
el diseño se ve como
Ahora escribamos una prueba para nuestro Actividad principal
clase. Ir a tu Actividad principal
clase, mueva el cursor a la Actividad principal
nombre y presione Shift-Control-T. Seleccionar Crear nueva prueba ... en el menú emergente.
presione el DE ACUERDO botón, y aparece otro diálogo. Elegir la prueba de android directorio y haga clic en el DE ACUERDO botón una vez más. Tenga en cuenta que debido a que estamos escribiendo una prueba de instrumentación (pruebas específicas de Android SDK), los casos de prueba residen en el prueba de android / java carpeta.
Ahora, Android Studio ha creado con éxito una clase de prueba para nosotros. Por encima del nombre de la clase, incluya esta anotación: @RunWith (AndroidJUnit4 :: class)
.
importar android.support.test.runner.AndroidJUnit4 importar org.junit.runner.RunWith @RunWith (AndroidJUnit4 :: class) class MainActivityTest
Esta anotación significa que todas las pruebas en esta clase son pruebas específicas de Android.
Como queremos probar una actividad, tenemos que hacer una pequeña configuración. Necesitamos informar a Espresso qué actividad abrir o iniciar antes de ejecutar y destruir después de ejecutar cualquier método de prueba.
import android.support.test.rule.ActivityTestRule import android.support.test.runner.AndroidJUnit4 import org.junit.Rule import org.junit.runner.RunWith @RunWith (AndroidJUnit4 :: class) class MainActivityTest @Rule @vmcc activityRule = ActivityTestRule(MainActivity :: class.java)
Tenga en cuenta que el @Regla
anotación significa que esta es una regla de prueba JUnit4. Las reglas de prueba de JUnit4 se ejecutan antes y después de cada método de prueba (anotadas con @Prueba
). En nuestro propio escenario, queremos lanzar Actividad principal
antes de cada método de prueba y destruirlo después.
También incluimos el @JvmField
Anotación de Kotlin. Esto simplemente indica al compilador que no genere captadores y definidores para la propiedad y, en cambio, lo exponga como un simple campo Java..
Aquí están los tres pasos principales para escribir una prueba de Espresso:
Vista de texto
o Botón
) quieres probar.Los siguientes tipos de anotaciones se pueden aplicar a los métodos utilizados dentro de la clase de prueba.
@Antes de clase
: esto indica que el método estático al que se aplica esta anotación debe ejecutarse una vez y antes de todas las pruebas en la clase. Esto podría usarse, por ejemplo, para configurar una conexión a una base de datos. @Antes de
: indica que el método al que se adjunta esta anotación debe ejecutarse antes de cada método de prueba en la clase.@Prueba
: indica que el método al que se adjunta esta anotación debe ejecutarse como un caso de prueba.@Después
: indica que el método al que se adjunta esta anotación debe ejecutarse después de cada método de prueba. @Después de clases
: indica que el método al que se adjunta esta anotación debe ejecutarse después de que se hayan ejecutado todos los métodos de prueba en la clase. Aquí, normalmente cerramos los recursos que se abrieron en @Antes de clase
. Ver
Utilizando a la vista()
En nuestro Actividad principal
archivo de diseño, solo tenemos un widget-el Iniciar sesión
botón. Probemos un escenario donde un usuario encuentre ese botón y haga clic en él.
importar android.support.test.espresso.Espresso.onView importar android.support.test.espresso.matcher.ViewMatchers.withId //… @RunWith (AndroidJUnit4 :: class) clase MainActivityTest //… @Test @Throws (Excepción: : class) fun clickLoginButton_opensLoginUi () onView (withId (R.id.btn_login))
Para encontrar widgets en Espresso, hacemos uso del a la vista()
método estático (en lugar de findViewById ()
). El tipo de parámetro que suministramos a a la vista()
es un Matcher
. Tenga en cuenta que el Matcher
API no proviene del SDK de Android, sino del Proyecto Hamcrest. La biblioteca de combinaciones de Hamcrest está dentro de la biblioteca de espresso que sacamos a través de Gradle.
los onView (withId (R.id.btn_login))
devolverá un ViewInteraction
eso es para un Ver
cuya ID es R.id.btn_login
. En el ejemplo anterior, usamos withId ()
para buscar un widget con un id dado. Otros comparadores de vistas que podemos usar son:
conTexto ()
: devuelve un matcher que coincide Vista de texto
basado en su valor de propiedad de texto.withHint ()
: devuelve un matcher que coincide Vista de texto
basado en su valor de propiedad de pista.conTagKey ()
: devuelve un matcher que coincide Ver
basado en claves de etiquetas.withTagValue ()
: devuelve un matcher que coincide Ver
s basado en valores de propiedad de etiqueta.Primero, probemos para ver si el botón se muestra realmente en la pantalla.
onView (withId (R.id.btn_login)). check (coincide (isDisplayed ()))
Aquí, solo estamos confirmando si el botón con la ID dada (R.id.btn_login
) es visible para el usuario, por lo que usamos el comprobar()
método para confirmar si el subyacente Ver
tiene un cierto estado, en nuestro caso, si es visible.
los partidos()
Método estático devuelve un genérico ViewAssertion
que afirma que existe una vista en la jerarquía de vistas y que coincide con el coincidente de vista dado. Ese visor de coincidencias dado se devuelve llamando se visualiza()
. Según lo sugerido por el nombre del método, se visualiza()
es un matcher que coincide Ver
s que se muestran actualmente en la pantalla para el usuario. Por ejemplo, si queremos comprobar si un botón está habilitado, simplemente pasamos está habilitado()
a partidos()
.
Otros concordantes de vistas populares que podemos pasar a la partidos()
método son:
hasFocus ()
: devuelve un matcher que coincide Ver
s que actualmente tienen foco.está chequeado()
: devuelve un comparador que acepta si y solo si la vista es un CompoundButton
(o subtipo de) y está en estado marcado. Lo contrario de este método es isNotChecked ()
. isSelected ()
: devuelve un matcher que coincide Ver
s que son seleccionados.Para ejecutar la prueba, puede hacer clic en el triángulo verde junto al método o al nombre de la clase. Al hacer clic en el triángulo verde al lado del nombre de la clase, se ejecutarán todos los métodos de prueba en esa clase, mientras que el que está al lado del método ejecutará la prueba solo para ese método.
¡Hurra! Nuestra prueba pasó!
En un ViewInteraction
objeto que se devuelve llamando a la vista()
, Podemos simular acciones que un usuario puede realizar en un widget. Por ejemplo, podemos simular una acción de clic simplemente llamando al hacer clic()
método estático dentro de la VerAcciones
clase. Esto devolverá un ViewAction
objeto para nosotros.
La documentación dice que ViewAction
es:
Responsable de realizar una interacción en el elemento Ver dado.
@Test fun clickLoginButton_opensLoginUi () //… onView (withId (R.id.btn_login)). Perform (click ())
Realizamos un evento clic por primera llamada. realizar()
. Este método realiza la (s) acción (es) dada (s) en la vista seleccionada por el comparador de vista actual. Tenga en cuenta que podemos pasarle una sola acción o una lista de acciones (ejecutadas en orden). Aquí lo dimos. hacer clic()
. Otras posibles acciones son:
teclee el texto()
para imitar escribiendo texto en una Editar texto
.Borrar texto()
para simular la limpieza de texto en una Editar texto
.haga doble clic()
para simular hacer doble clic en un Ver
.longClick ()
para imitar a un clic largo Ver
.scrollTo ()
para simular el desplazamiento de un ScrollView
a un particular Ver
eso es visible. deslizar a la izquierda()
para simular deslizar de derecha a izquierda a través del centro vertical de una Ver
.Muchas simulaciones más se pueden encontrar dentro de la VerAcciones
clase.
Vamos a completar nuestra prueba, para validar que el Iniciar sesiónActividad
la pantalla se muestra cada vez que el Iniciar sesión Se hace clic en el botón. Aunque ya hemos visto como usar comprobar()
en un ViewInteraction
, Usémoslo de nuevo, pasándolo por otro. ViewAssertion
.
@Test fun clickLoginButton_opensLoginUi () //… onView (withId (R.id.tv_login)). Check (coincide (isDisplayed ()))
Dentro de Iniciar sesiónActividad
archivo de diseño, aparte de Editar texto
s y a Botón
, también tenemos un Vista de texto
con identificación R.id.tv_login
. Así que simplemente hacemos un cheque para confirmar que el Vista de texto
es visible para el usuario.
Ahora puedes volver a ejecutar la prueba.!
Tus pruebas deberían pasar con éxito si seguiste todos los pasos correctamente.
Esto es lo que sucedió durante el proceso de ejecución de nuestras pruebas:
Actividad principal
utilizando la actividadRegulación
campo.R.id.btn_login
) era visible (se visualiza()
) al usuario.hacer clic()
) en ese botón.Iniciar sesiónActividad
se le mostró al usuario al verificar si una Vista de texto
con identificación R.id.tv_login
en el Iniciar sesiónActividad
es visible.Siempre puede consultar la hoja de trucos de Espresso para ver los diferentes igualadores de vista, ver acciones y ver aserciones disponibles.
Iniciar sesiónActividad
PantallaAquí está nuestro LoginActivity.kt:
import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.widget.Button import android.widget.EditText import android.widget.TextView class LoginActivity: AppCompatActivity () private lateinit var usernameEditText: Edit loginTitleTextView: TextView private lateinit var passwordEditText: EditText recreat recreate .parte. = findViewById (R.id.et_password) submitButton = findViewById (R.id.btn_submit) loginTitleTextView = findViewById (R.id.tv_login) submitButton.permas en el / las (los) nombre de usuario (persona / nombre / usuario / siguiente). text.toString () == "password") loginTitleTextView.text = "Success" else else loginTitleTextView.text = "Failure"
En el código anterior, si el nombre de usuario ingresado es "chike" y la contraseña es "contraseña", el inicio de sesión es exitoso. Para cualquier otra entrada, es un fracaso. Ahora vamos a escribir una prueba de espresso para esto!
Ir LoginActivity.kt, mover el cursor a la Iniciar sesiónActividad
nombre y presione Shift-Control-T. Seleccionar Crear nueva prueba ... en el menú emergente. Siga el mismo proceso que hicimos para MainActivity.kt, y haga clic en el DE ACUERDO botón.
import android.support.test.espresso.Espresso import android.support.test.espresso.Espresso.onView import android.support.test.espresso.action.ViewActions import android.support.test.espresso.assertion.ViewAssertions.matches import android .support.test.espresso.matcher.ViewMatchers.withId import android.support.test.espresso.matcher.ViewMatchers.withText import android.support.test.rule.ActivityTestRule import android.support.test.runner.AndroidJUnit4 import org.junit .Rule import org.junit.Test import org.junit.runner.RunWith @RunWith (AndroidJUnit4 :: class) clase LoginActivityTest @Rule @JvmField var activityRule = ActivityTestRule(LoginActivity :: class.java) private val username = "chike" private val password = "password" @Test fun ClickLoginButton_opensLoginUi () onView (withId (R.id.et_username)). Perform (ViewActions.typeText (nombre de usuario)) onView (withId (R.id.et_password)). perform (ViewActions.typeText (password)) onView (withId (R.id.btn_submit)). perform (ViewActions.scrollTo (), ViewActions.click ()) Espresso.onView (withId (R.id.tv_login)) .check (coincide con (withText ("Success")))
Esta clase de prueba es muy similar a la primera. Si corremos la prueba, nuestra Iniciar sesiónActividad
se abre la pantalla. El nombre de usuario y la contraseña se escriben en el R.id.et_username
y R.id.et_password
campos respectivamente. A continuación, Espresso hará clic en el Enviar botón (R.id.btn_submit
). Esperará hasta que un Ver
con identificación R.id.tv_login
se puede encontrar con la lectura de texto Éxito.
RecyclerView
RecyclerViewActions
es la clase que expone un conjunto de API para operar en una RecyclerView
. RecyclerViewActions
es parte de un artefacto separado dentro del expreso-contrib
artefacto, que también debe ser añadido a construir.gradle:
androidTestImplementation 'com.android.support.test.espresso: espresso-contrib: 3.0.2'
Tenga en cuenta que este artefacto también contiene la API para la interfaz de usuario que prueba el cajón de navegación a través de Cajón de acciones
y Cajoneros
.
@RunWith (AndroidJUnit4 :: class) class MyListActivityTest //… @Test fun clickItem () onView (withId (R.id.rv)) .perform (RecyclerViewActions .actionOnItemAtPosition(0, ViewActions.click ()))
Para hacer clic en un elemento en cualquier posición en una RecyclerView
, invocamos actionOnItemAtPosition ()
. Tenemos que darle un tipo de artículo. En nuestro caso, el artículo es el ViewHolder
clase dentro de nuestro RandomAdapter
. Este método también toma en dos parámetros; el primero es la posición, y el segundo es la acción (ViewActions.click ()
).
Otro RecyclerViewActions
que se pueden realizar son:
actionOnHolderItem ()
: realiza un ViewAction
en una vista emparejada por viewHolderMatcher
. Esto nos permite igualarlo con lo que contiene el ViewHolder
en lugar de la posición. scrollToPosition ()
: devuelve un ViewAction
que se desplaza RecyclerView
a una posición.A continuación (una vez que la "pantalla de agregar nota" esté abierta), ingresaremos el texto de nuestra nota y guardaremos la nota. No necesitamos esperar a que se abra la nueva pantalla: Espresso lo hará automáticamente por nosotros. Espera hasta una vista con el id. R.id.add_note_title
puede ser encontrado.
El espresso hace uso de otro artefacto llamado intenciones de expreso
para los intentos de prueba. Este artefacto es solo otra extensión de Espresso que se enfoca en la validación y burla de los Intentos. Veamos un ejemplo.
Primero, tenemos que tirar del intenciones de expreso
biblioteca en nuestro proyecto.
androidTestImplementation 'com.android.support.test.espresso: espresso-intents: 3.0.2'
import android.support.test.espresso.intent.rule.IntentsTestRule import android.support.test.runner.AndroidJUnit4 import org.junit.Rule import org.junit.runner.RunWith @RunWith (AndroidJUnit4 :: class) clase PickContactivoactividad Regla @JvmField var intentRule = IntentsTestRule(PickContactActivity :: class.java)
IntentsTestRule
se extiende ActivityTestRule
, por lo que ambos tienen comportamientos similares. Esto es lo que dice el doc:
Esta clase es una extensión deActivityTestRule
, que inicializa Espresso-Intents antes de cada prueba anotada conPrueba
y libera Espresso-Intents después de cada prueba. La Actividad finalizará después de cada prueba y esta regla se puede utilizar de la misma manera queActivityTestRule
.
La principal característica diferenciadora es que tiene funcionalidades adicionales para la prueba. startActivity ()
y startActivityForResult ()
con burlas y talones.
Ahora vamos a probar un escenario en el que un usuario hará clic en un botón (R.id.btn_select_contact
) en la pantalla para elegir un contacto de la lista de contactos del teléfono.
//… @Test fun stubPick () var result = Instrumentation.ActivityResult (Activity.RESULT_OK, Intent (null, ContactsContract.Contacts.CONTENT_URI)) intencional (hasAction (Intent.ACTION_PICK)) .responWith (resultado) onView (withId () R.id.btn_select_contact)). Realiza (click ()) intencionada (allOf (toPackage ("com.google.android.contacts"), hasAction (Intent.ACTION_PICK), hasData (ContactsContract.Contacts.CONTENT_URI))) // ...
Aquí estamos usando pretendiendo ()
desde el intenciones de expreso
biblioteca para configurar un talón con una respuesta simulada para nuestra ACTION_PICK
solicitud. Esto es lo que sucede en PickContactActivity.kt cuando el usuario hace clic en el botón con id R.id.btn_select_contact
para elegir un contacto.
diversión pickContact (v: Ver) val i = Intent (Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI) startActivityForResult (i, PICK_REQUEST)
pretendiendo ()
toma en un Matcher
que coincida con los intentos para los que se debe proporcionar una respuesta aplastada. En otras palabras, la Matcher
identifica qué solicitud estás interesado en aplastar. En nuestro propio caso, hacemos uso de hasAction ()
(un método de ayuda en IntentMatchers
) para encontrar nuestro ACTION_PICK
solicitud. Entonces invocamos responder con()
, que establece el resultado para onActivityResult ()
. En nuestro caso, el resultado ha Actividad.RESULTADO_OK
, simulando al usuario seleccionando un contacto de la lista.
Luego simulamos haciendo clic en el botón seleccionar contacto, que llama startActivityForResult ()
. Tenga en cuenta que nuestro talón envió la respuesta simulada a onActivityResult ()
.
Finalmente, utilizamos el destinado a()
método de ayuda para simplemente validar que las llamadas a startActivity ()
y startActivityForResult ()
fueron hechos con la información correcta.
En este tutorial, aprendió a usar fácilmente el marco de prueba de Espresso en su proyecto de Android Studio para automatizar su flujo de trabajo de prueba.
Recomiendo consultar la documentación oficial para obtener más información sobre cómo escribir pruebas de UI con Espresso.