Flujo crítico con Espresso y Screen Object - 1Adevelopers/FlorAppMovil GitHub Wiki
Esta sección documenta la prueba automatizada de interfaz del flujo crítico de login realizada con Espresso, organizada con el patrón Screen Object e incluyendo chequeos automáticos de accesibilidad.
| Dato | Valor |
|---|---|
| Herramienta | Espresso 3.5.1 + espresso-accessibility 3.5.1 |
| Lenguaje / framework | Java + JUnit 4 (AndroidJUnit4) |
| Tipo de prueba | Instrumentada de interfaz (corre en el dispositivo) |
| Patrón | Screen Object (una clase por pantalla) |
| ID automatización | AUT-ESP-01 |
| Clase de test | app/src/androidTest/java/com/ispc/florappmovil/flujos/LoginFlujoCriticoTest.java |
| Dispositivo probado | Samsung Galaxy J7 Pro (SM-J730GM), Android 9, por USB |
| Responsable | Eric Heredia |
| Reporte | LoginFlujoCriticoTest |
1. ¿Qué es cada cosa?
Espresso
Es la herramienta oficial de Google para probar la interfaz de apps Android. El test se ejecuta dentro de la app, en el dispositivo, y simula lo que haría un usuario: tocar botones, escribir y verificar lo que se ve en pantalla.
| Appium (AUT-LOG-01) | Espresso (AUT-ESP-01) | |
|---|---|---|
| Dónde corre | Fuera de la app, desde la PC | Dentro del proyecto (androidTest) |
| Qué necesita | Node.js, servidor Appium, driver UiAutomator2 | Nada extra: viene con Android Studio |
| Cómo encuentra los elementos | Texto del id (com.ispc.florappmovil:id/btnLogin) |
Directo con R.id.btnLogin |
| Tipo de prueba | Caja negra | Caja gris (conoce el código de la app) |
Screen Object
Es un patrón para organizar las pruebas de interfaz: se crea una clase por pantalla que sabe cómo manejarla (qué botones tiene, cómo se completa). El test solo llama a esos métodos, por lo que se lee casi como el caso de prueba escrito:
new IngresoScreen()
.verificarVisible()
.tocarIniciarSesion()
.iniciarSesion(EMAIL, PASSWORD)
.verificarSesionActiva()
.presionarAtras()
.aceptarCerrarSesion()
.verificarVisible();
Ventaja: si cambia un id en un layout, se corrige en una sola clase (la Screen) y no en todos los tests.
Flujo crítico
Es el recorrido más importante de la app: si falla, la app no cumple su función. En FlorApp es el inicio y cierre de sesión.
2. Estructura
app/src/androidTest/java/com/ispc/florappmovil/
├── screens/
│ ├── BaseScreen.java → método común esperarVisible()
│ ├── IngresoScreen.java → pantalla de Ingreso
│ ├── LoginScreen.java → pantalla de Login
│ └── GaleriaScreen.java → Galería y modal de salida
└── flujos/
└── LoginFlujoCriticoTest.java → el test (AUT-ESP-01)
| Clase | Responsabilidad | Métodos |
|---|---|---|
BaseScreen |
Base común de todas las Screens | esperarVisible(): reintenta hasta 15 s hasta que una vista aparezca (Espresso no espera la respuesta del servidor Django) |
IngresoScreen |
Pantalla de Ingreso (IngresoActivity) |
verificarVisible(), tocarIniciarSesion() |
LoginScreen |
Pantalla de Login (LoginActivity) |
escribirEmail(), escribirPassword(), tocarIngresar(), iniciarSesion() |
GaleriaScreen |
Galería (GaleriaActivity) y modal de salida |
verificarSesionActiva(), presionarAtras(), aceptarCerrarSesion() |
3. Flujo automatizado (AUT-ESP-01)
| Paso | Acción | Verificación |
|---|---|---|
| 1 | Se borra la sesión guardada y se abre la pantalla de Ingreso | Se ven los botones Iniciar sesión, Registrarse e Ingresar como invitado |
| 2 | Toca "Iniciar sesión" | Se abre la pantalla de Login |
| 3 | Escribe email y contraseña y toca "Iniciar sesión" | — |
| 4 | Espera la respuesta del backend | La barra de navegación muestra "Mi Perfil" (sesión activa) |
| 5 | Presiona "Atrás" | Aparece el modal "¿Deseás cerrar sesión?" |
| 6 | Toca "Aceptar" en el modal | Vuelve a la pantalla de Ingreso |
Acciones de Espresso utilizadas
| Código | Significado |
|---|---|
onView(withId(R.id.btnLogin)) |
Busca la vista con ese id |
.perform(click()) |
La toca |
.perform(typeText("..."), closeSoftKeyboard()) |
Escribe el texto y cierra el teclado |
.check(matches(isDisplayed())) |
Verifica que se vea |
.check(matches(withText("Mi Perfil"))) |
Verifica el texto exacto |
pressBack() |
Presiona el botón Atrás del dispositivo |
.inRoot(isDialog()) |
Busca la vista dentro del modal |
4. Chequeos automáticos de accesibilidad
En el test se activa:
@BeforeClass
public static void activarChequeosDeAccesibilidad() {
AccessibilityChecks.enable().setRunChecksFromRootView(true);
}
Desde ese momento, cada vez que el test toca o escribe algo, Espresso analiza toda la pantalla con el Accessibility Test Framework de Google. Si encuentra un problema, el test falla e indica la vista y el motivo.
| Chequeo | Regla |
|---|---|
| Contraste de texto | Mínimo 4.5:1 (3:1 en texto grande) – WCAG 2.1, 1.4.3 |
| Tamaño táctil | Mínimo 48×48 dp – WCAG 2.1, 2.5.5 / guía de Android |
| Etiquetas | Elementos interactivos con texto o contentDescription para TalkBack |
Hallazgos y correcciones
| Bug | Issue | Pantalla | Hallazgo (chequeo) | Corrección |
|---|---|---|---|---|
| BUG-ACC-01 | #66 | Login | El enlace "¿No tenés cuenta? Registrate" (tvIrARegistro) medía 40dp de alto (TouchTargetSizeCheck) |
android:minHeight="48dp" y android:gravity="center" en activity_login.xml |
| BUG-ACC-02 | #67 | Galería | La etiqueta de categoría (tvCategoria) tenía texto #FFFFFF sobre #BFBFBF: contraste 1.84:1 (TextContrastCheck) |
Texto @color/texto_principal (#334155) en item_ficha.xml: contraste 5.6:1 |
Luego de las correcciones, el flujo completo se ejecuta sin hallazgos.
5. Configuración
En app/build.gradle, dentro de dependencies:
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation 'androidx.test.espresso:espresso-accessibility:3.5.1'
espresso-core ya estaba en el proyecto; se agregó espresso-accessibility con la misma versión. Ambas son androidTestImplementation: solo se usan en las pruebas y no se incluyen en la app.
6. Ejecutar la prueba
Requisitos
- Celular conectado por USB, desbloqueado y con depuración USB activada.
- Backend Django encendido:
python manage.py runserver 0.0.0.0:8000. - Usuario de prueba registrado:
[email protected]. - No hace falta Appium.
Desde Android Studio
Abrir LoginFlujoCriticoTest y tocar el ▶ verde junto a la clase → Run 'LoginFlujoCriticoTest'.
Desde la terminal (PowerShell, raíz del proyecto)
.\gradlew.bat :app:connectedDebugAndroidTest "-Pandroid.testInstrumentationRunnerArguments.class=com.ispc.florappmovil.flujos.LoginFlujoCriticoTest"
Informe HTML
app/build/reports/androidTests/connected/debug/index.html
Abrirlo con start app\build\reports\androidTests\connected\debug\index.html.
7. Resultado de la ejecución
| Ejecución | Resultado |
|---|---|
| 1ª | ❌ Falla por accesibilidad en Login: BUG-ACC-01 (tamaño táctil) |
| 2ª (tras corregir Login) | ❌ Falla por accesibilidad en Galería: BUG-ACC-02 (contraste) |
| 3ª (tras corregir Galería) | ✅ 1 de 1 test aprobado, sin hallazgos de accesibilidad |
Ambiente: Samsung Galaxy J7 Pro (SM-J730GM), Android 9 – Backend Django local – 13/10/2026.
8. Problemas frecuentes
| Síntoma | Causa probable y solución |
|---|---|
AccessibilityViewCheckException |
El chequeo encontró un problema real de accesibilidad. El mensaje indica la vista (res-name) y el motivo. Registrarlo como bug y corregir el layout. |
NoMatchingViewException o timeout esperando "Mi Perfil" |
El login no respondió: revisar que Django esté encendido, la IP en local.properties y que el usuario exista. |
AccessibilityChecks en rojo |
Falta la dependencia espresso-accessibility o el Sync Now. |
| Clases de la app en rojo dentro del test | El archivo quedó en test en lugar de androidTest. |
| No aparece el reporte HTML | Ejecutar desde la terminal con Gradle (el botón ▶ no siempre lo genera). |
9. Cómo agregar otro flujo
- Si el flujo pasa por una pantalla nueva, crear su Screen en
screens/(extendiendoBaseScreen), con un método por acción. - Crear el test en
flujos/encadenando los métodos de las Screens. - Mantener
AccessibilityChecks.enable()para revisar también la accesibilidad de las pantallas nuevas. - Registrar el ID en la planilla de casos de prueba (columna "Herramienta e ID del test"), por ejemplo:
Espresso + Accessibility Checks – AUT-ESP-02 (RegistroFlujoTest)