Inventario de pruebas 2 - sjfuentes-uniandes/ing-sw-app-moviles GitHub Wiki

Documentación de Pruebas UI - HU004 Detalle de Artista

📋 Información General

Historia de Usuario: HU004 - Consultar Información Detallada de un Artista
Tipo de Pruebas: UI/Instrumentadas con Espresso
Ubicación: app/src/androidTest/java/com/example/vinilos/HU04-detalle-artista/ArtistDetailFlowTest.kt
Framework: Android Espresso + JUnit4
Nivel: Integration/E2E (End-to-End)


🎯 Objetivo de las Pruebas

Validar el flujo completo de la funcionalidad de consulta de detalle de artista desde la perspectiva del usuario, cubriendo:

  1. Navegación desde la lista de artistas al detalle
  2. Visualización correcta de la información del artista
  3. Retorno desde el detalle a la lista
  4. Comportamiento de navegación consistente entre pantallas

🧪 Casos de Prueba Implementados

1. navigateToArtistDetail_and_backToList()

Descripción Funcional:
Verifica que un usuario pueda navegar desde la lista de artistas al detalle de un artista específico y regresar correctamente a la lista.

Flujo de Usuario:

  1. Usuario abre la aplicación
  2. Usuario navega al tab "Artists"
  3. Sistema carga y muestra la lista de artistas
  4. Usuario hace clic en el primer artista de la lista
  5. Sistema muestra la pantalla de detalle con la información del artista
  6. Usuario presiona el botón de regreso ("<")
  7. Sistema regresa a la lista de artistas

Descripción Técnica:

@Test
fun navigateToArtistDetail_and_backToList()

Pasos de Ejecución:

# Acción Selector Tipo Objetivo
1 Click en tab Artists R.id.navigation_artists Bottom Navigation Navegación a módulo
2 Espera de carga Thread.sleep(3000) Delay fijo Mitigar cold start del backend
3 Verificar lista visible R.id.artists_recycler_view RecyclerView Validar carga de datos
4 Click en primer artista R.id.artists_recycler_view + ViewAction personalizado RecyclerView Item Navegación a detalle
5 Verificar imagen de artista R.id.artistImage ImageView Validar UI de detalle
6 Verificar nombre de artista R.id.artistName TextView Validar dato principal
7 Verificar label de descripción R.id.descriptionLabel con texto "Description" TextView Validar estructura UI
8 Click en botón back R.id.btnBack ImageButton Acción de retorno
9 Verificar lista visible nuevamente R.id.artists_recycler_view RecyclerView Validar navegación correcta

Assertions (Verificaciones):

  • ✅ RecyclerView de artistas se muestra después de navegar al tab
  • ✅ Imagen del artista es visible en el detalle
  • ✅ Nombre del artista es visible en el detalle
  • ✅ Label "Description" está presente con el texto correcto
  • ✅ RecyclerView de artistas se muestra nuevamente tras presionar back

Cobertura Funcional:

  • Navegación entre pantallas (lista ↔ detalle)
  • Carga de datos desde API (con tolerancia a cold start)
  • Renderizado de componentes UI del detalle
  • Botón de regreso funcional

Riesgos Mitigados:

  • Backend en cold start (Render): espera de 3 segundos
  • Race conditions de carga asíncrona

2. navigateHomeThenArtists_alwaysShowsArtistsList()

Descripción Funcional:
Verifica que al navegar entre Home y Artists, siempre se muestre la lista de artistas (no un detalle residual del estado anterior).

Flujo de Usuario:

  1. Usuario abre la aplicación
  2. Usuario navega a Home
  3. Usuario navega al tab "Artists"
  4. Sistema muestra la lista de artistas (no un detalle guardado en memoria)

Descripción Técnica:

@Test
fun navigateHomeThenArtists_alwaysShowsArtistsList()

Pasos de Ejecución:

# Acción Selector Tipo Objetivo
1 Click en tab Home R.id.navigation_home Bottom Navigation Cambio de contexto
2 Click en tab Artists R.id.navigation_artists Bottom Navigation Navegación al módulo
3 Verificar lista visible R.id.artists_recycler_view RecyclerView Validar estado inicial correcto

Assertions (Verificaciones):

  • ✅ RecyclerView de artistas siempre se muestra al entrar al tab Artists
  • ✅ No se muestra un detalle residual de una navegación anterior

Cobertura Funcional:

  • Gestión correcta de back stack por MainActivity
  • Limpieza de navegación entre tabs (NavOptions aplicado)
  • Prevención de estado inconsistente en la navegación

Casos de Borde Validados:

  • Usuario navega Artists → Detalle → Home → Artists: debe ver lista, no detalle
  • Estado de navegación no persiste incorrectamente entre cambios de tab

🛠️ Implementación Técnica

ViewAction Personalizado para RecyclerView

Problema Resuelto:
Evitar dependencia de espresso-contrib que requiere sincronización compleja de Gradle y aumenta el tamaño del APK de pruebas.

Solución Implementada:

private fun clickOnRecyclerViewItem(position: Int): ViewAction {
    return object : ViewAction {
        override fun getConstraints(): Matcher<View> {
            return isAssignableFrom(RecyclerView::class.java)
        }

        override fun getDescription(): String {
            return "Click on RecyclerView item at position $position"
        }

        override fun perform(uiController: UiController, view: View) {
            val recyclerView = view as RecyclerView
            val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
            viewHolder?.itemView?.performClick()
        }
    }
}

Características:

  • ✅ Accede directamente al ViewHolder por posición
  • ✅ Ejecuta performClick() en la vista del item
  • ✅ No requiere bibliotecas externas adicionales
  • ✅ Más ligero que RecyclerViewActions.actionOnItemAtPosition()

Limitaciones:

  • Solo funciona si el ViewHolder ya está vinculado (visible en pantalla)
  • No hace scroll automático; asume que el item en posición 0 es visible

📦 Configuración y Dependencias

Dependencias de Pruebas (build.gradle.kts)

androidTestImplementation(libs.androidx.junit)              // JUnit para Android
androidTestImplementation(libs.androidx.espresso.core)      // Espresso Core
androidTestImplementation("androidx.test:runner:1.6.2")     // Test Runner
androidTestImplementation("androidx.test:rules:1.6.0")      // Activity Test Rules

Nota: No se requiere espresso-contrib gracias al ViewAction personalizado.

Test Runner

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

Anotaciones Utilizadas

  • @LargeTest: Indica que son pruebas de integración (E2E), con tiempo de ejecución mayor
  • @RunWith(AndroidJUnit4::class): Ejecutor de pruebas para Android
  • @Rule: Regla de JUnit para lanzar la actividad principal
  • @Test: Marca los métodos como casos de prueba

🚀 Ejecución de las Pruebas

Desde Android Studio

  1. Ejecutar todos los tests de HU04:

    • Navegar a ArtistDetailFlowTest.kt
    • Click derecho en el nombre de la clase
    • Seleccionar "Run 'ArtistDetailFlowTest'"
  2. Ejecutar un test individual:

    • Click en el ícono ▶️ junto al método @Test
    • Seleccionar "Run 'navigateToArtistDetail_and_backToList()'"

Desde Terminal

# Ejecutar todos los tests instrumentados
./gradlew connectedAndroidTest

# Ejecutar solo los tests de HU04
./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.example.vinilos.HU04_detalle_artista.ArtistDetailFlowTest

Requisitos de Ejecución

  • ✅ Emulador o dispositivo físico conectado
  • ✅ API level 24 o superior (minSdk configurado en el proyecto)
  • ✅ Conexión a Internet (para acceder al backend de la API)
  • ⚠️ Backend disponible en: https://ing-sw-api-mobile.onrender.com/bands

Tiempo estimado de ejecución:

  • Primer test: ~6-8 segundos (incluye cold start del backend)
  • Segundo test: ~2-3 segundos

📊 Cobertura de la Funcionalidad

Escenarios Cubiertos

Escenario Estado Test
Navegación a lista de artistas ✅ Cubierto ambos tests
Click en un artista de la lista ✅ Cubierto Test 1
Visualización de detalle completo ✅ Cubierto Test 1
Botón de regreso desde detalle ✅ Cubierto Test 1
Retorno a lista tras back ✅ Cubierto Test 1
Navegación Home → Artists → Lista ✅ Cubierto Test 2
Estado de navegación limpio ✅ Cubierto Test 2

🐛 Manejo de Errores y Casos Especiales

1. Backend en Cold Start (Render)

Problema:
El backend alojado en Render puede tardar hasta 30 segundos en despertar si no ha recibido tráfico reciente.

Mitigación Actual:

Thread.sleep(3000)  // Espera de 3 segundos

Mejora Propuesta:
Implementar IdlingResource que espere hasta que el RecyclerView tenga al menos 1 item:

// Pseudo-código (no implementado)
class RecyclerViewIdlingResource(private val recyclerView: RecyclerView) : IdlingResource {
    override fun isIdleNow(): Boolean {
        return recyclerView.adapter?.itemCount ?: 0 > 0
    }
}

2. Elemento No Visible en RecyclerView

Problema:
Si el item en posición 0 no está visible (por scroll previo), findViewHolderForAdapterPosition() retorna null.

Manejo Actual:

viewHolder?.itemView?.performClick()  // Safe call, no falla si es null

Limitación:
El test pasaría silenciosamente sin hacer clic.

Mejora Propuesta:

val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
    ?: throw PerformException.Builder()
        .withActionDescription(this.description)
        .withViewDescription(HumanReadables.describe(view))
        .withCause(IllegalStateException("ViewHolder at position $position not found"))
        .build()
viewHolder.itemView.performClick()

3. Cambios en IDs de Recursos

Riesgo:
Si se renombran IDs en los layouts XML, los tests fallan con NoMatchingViewException.

Prevención:

  • Mantener IDs estables durante el desarrollo
  • Usar constantes centralizadas si hay múltiples referencias

Detección Temprana:

  • Los tests fallan inmediatamente en CI/CD
  • Error claro: No views in hierarchy found matching: with id: R.id.artists_recycler_view

📈 Métricas y Resultados Esperados

Criterios de Éxito

Métrica Valor Esperado Valor Actual
Tests pasando 2/2 (100%) ✅ 2/2
Tiempo de ejecución < 15 segundos ~8-10 seg
Cobertura de flujo principal 100% ✅ 100%
False positives 0 ✅ 0
Flakiness (inestabilidad) < 5% ⚠️ ~10% (cold start)

Causas de Fallo Comunes

  1. Backend no disponible:

    • Error: NetworkException o timeout
    • Solución: Verificar conexión a Internet y disponibilidad del endpoint
  2. Cambios en la UI:

    • Error: NoMatchingViewException
    • Solución: Actualizar IDs en los tests tras refactorización de layouts
  3. Datos del backend inconsistentes:

    • Error: Lista vacía o artista sin imagen
    • Solución: Usar mock del backend o validar datos de prueba

🔄 Mantenimiento y Evolución

Cuándo Actualizar los Tests

  • ✅ Al cambiar IDs de vistas en layouts
  • ✅ Al modificar el flujo de navegación (ej: agregar pantalla intermedia)
  • ✅ Al cambiar strings (ej: "Description" → "Descripción")
  • ✅ Al agregar nuevos campos en el detalle del artista

Versionado de los Tests

Estos tests están vinculados a:

  • HU004: Consultar Detalle de Artista
  • Sprint: 2 (ejemplo)
  • Versión de API: v1 (backend)

Documentación de Pruebas UI - HU07 Crear álbum

📋 Información General

Historia de Usuario: HU07 - Crear álbum

Tipo de Pruebas: UI/Instrumentadas con Espresso

Ubicación: app/src/androidTest/java/com/example/vinilos/HU07-crear-album/AddAlbumFragmentTest.kt

Framework: Android Espresso + JUnit4

Nivel: Integration/E2E (End-to-End)


🎯 Objetivo de las Pruebas

Validar el flujo completo de la creación de un álbum.

  1. Navegación desde el home a lista de álbumes
  2. Navegación desde lista de álbumes a formulario de creación
  3. Ingreso de datos en formulario y validaciones
  4. Selección de artista, imagen y tracks
  5. Creación de un álbum y navegación de regreso

🧪 Casos de Prueba Implementados

1. createAlbum_fillsFormAndSubmits_navigatesBack()

Descripción Funcional:
Verifica que un usuario pueda navegar desde el home hasta el formulario de creación de un álbum, completar todos los campos requeridos, seleccionar un artista, agregar una imagen, agregar tracks, y crear exitosamente un álbum que regrese al listado.

Flujo de Usuario:

  1. Usuario abre la aplicación
  2. Usuario hace click en "Albums" (botón de navegación)
  3. Sistema carga y muestra la lista de álbumes
  4. Usuario hace clic en "Crear álbum"
  5. Sistema muestra el formulario de crear álbum con título "Crear Album"
  6. Usuario llena información requerida:
    • Nombre del álbum
    • Descripción
    • Fecha de lanzamiento
    • Selecciona un artista de la lista
    • Género
    • Sello discográfico
    • Selecciona una imagen
    • Agrega un track
  7. Usuario hace clic en "Crear álbum"
  8. Sistema envía información y regresa a listado de álbumes

Descripción Técnica:

@Test
fun createAlbum_fillsFormAndSubmits_navigatesBack()

Pasos de Ejecución:

# Acción Selector Tipo Objetivo
1 Verificar botón Albums visible R.id.btn_albums Button Validar UI inicial
2 Click en botón Albums R.id.btn_albums Button Navegación a módulo de álbumes
3 Espera de carga Thread.sleep(2000) Delay fijo Mitigar cold start del backend
4 Verificar botón crear álbum visible R.id.add_album_button Button Validar carga de lista
5 Click en crear álbum R.id.add_album_button Button Navegación a formulario
6 Espera de carga Thread.sleep(2000) Delay fijo Esperar renderizado del formulario
7 Verificar título del formulario withText("Crear Album") TextView Validar pantalla correcta
8 Verificar campo nombre visible R.id.name_edit_text EditText Validar UI del formulario
9 Click y llenar nombre R.id.name_edit_text EditText Ingresar "Nuevo Álbum de Prueba"
10 Verificar campo descripción visible R.id.description_edit_text EditText Validar UI del formulario
11 Click y llenar descripción R.id.description_edit_text EditText Ingresar descripción de prueba
12 Verificar campo fecha visible R.id.release_date_edit_text EditText Validar UI del formulario
13 Llenar fecha de lanzamiento R.id.release_date_edit_text EditText Ingresar "2024-01-01"
14 Seleccionar artista Acceso directo al fragment Programático Seleccionar primer artista disponible
15 Verificar campo género visible R.id.genre_edit_text EditText Validar UI del formulario
16 Click y llenar género R.id.genre_edit_text EditText Ingresar "Rock"
17 Verificar campo sello visible R.id.record_label_edit_text EditText Validar UI del formulario
18 Click y llenar sello discográfico R.id.record_label_edit_text EditText Ingresar "Sony Music"
19 Mockear selección de imagen Intent.ACTION_GET_CONTENT Intent Mock Simular selección de imagen
20 Click en botón buscar imagen R.id.browse_image_button Button Abrir selector de imagen
21 Agregar track Acceso directo al fragment Programático Agregar "Demo Track A"
22 Scroll y verificar botón crear R.id.create_album_button Button Validar botón visible
23 Click en crear álbum R.id.create_album_button Button Enviar formulario
24 Espera de procesamiento Thread.sleep(1500) Delay fijo Esperar respuesta del servidor
25 Verificar regreso a lista R.id.add_album_button Button Validar navegación de regreso

Assertions (Verificaciones):

  • ✅ Botón de Albums se muestra en la pantalla inicial
  • ✅ Botón de crear álbum se muestra después de navegar al módulo
  • ✅ Título "Crear Album" es visible en el formulario
  • ✅ Todos los campos del formulario son visibles y editables:
    • Campo nombre
    • Campo descripción
    • Campo fecha de lanzamiento
    • Campo género
    • Campo sello discográfico
  • ✅ Artista se selecciona correctamente desde la lista disponible
  • ✅ Imagen se selecciona mediante mock de Intent
  • ✅ Track se agrega correctamente a la lista
  • ✅ Botón de crear álbum es visible y clickeable
  • ✅ Después de crear, se regresa al listado de álbumes (botón crear visible nuevamente)

Cobertura Funcional:

  • Navegación entre pantallas (home → lista → formulario → lista)
  • Carga de datos desde API (artistas disponibles)
  • Renderizado de componentes UI del formulario
  • Validación de campos requeridos
  • Selección de artista desde lista desplegable
  • Selección de imagen mediante Intent
  • Agregado de tracks dinámicamente
  • Envío de formulario y creación de álbum
  • Navegación de regreso tras creación exitosa

Riesgos Mitigados:

  • Backend en cold start (Render): esperas de 2 segundos en puntos críticos
  • Race conditions de carga asíncrona de artistas
  • Selección de imagen requiere mock de Intent (no se puede abrir selector real en tests)
  • Interacciones programáticas necesarias para campos complejos (artista, tracks)

Notas Técnicas:

  • Uso de forceClick() personalizado para asegurar clicks en elementos que pueden no estar completamente interactuables
  • Acceso directo al fragment mediante activityRule.scenario.onActivity para operaciones complejas (selección de artista, agregado de tracks)
  • Mock de Intent para simular selección de imagen sin abrir el selector real del sistema
  • Uso de Intents.init() y Intents.release() para manejo de Intents mockeados
  • Cierre de teclado virtual (closeSoftKeyboard()) para evitar interferencias en las interacciones

Documentación de Pruebas UI - HU002 Detalle de Álbum

Información General

Historia de Usuario: HU002 - Consultar Información Detallada de un Álbum Tipo de Pruebas: UI/Instrumentadas con Espresso Ubicación: app/src/androidTest/java/com/example/vinilos/HU02-detalle-album/AlbumDetailFlowTest.kt Framework: Android Espresso + JUnit4 Nivel: Integration/E2E (End-to-End)


Objetivo de las Pruebas

Validar el flujo completo de la funcionalidad de consulta de detalle de álbum desde la perspectiva del usuario, cubriendo:

  1. Navegación desde la lista de álbumes al detalle.
  2. Visualización correcta de la información del álbum.
  3. Retorno desde el detalle a la lista.
  4. Comportamiento de navegación consistente entre pantallas.

Casos de Prueba Implementados

1. navigateToAlbumDetail_and_backToList()

Descripción Funcional: Verifica que un usuario pueda navegar desde la lista de álbumes al detalle de un álbum específico y regresar correctamente a la lista.

Flujo de Usuario: 1.Usuario abre la aplicación. 2.Usuario navega al tab "Albums". 3.Sistema carga y muestra la lista de álbumes. 4.Usuario hace clic en el primer álbum de la lista. 5.Sistema muestra la pantalla de detalle con la información del álbum. 6.Usuario presiona el botón de regreso ("<"). 7.Sistema regresa a la lista de álbumes.

Descripción Técnica:

@Test
fun navigateToAlbumDetail_and_backToList()

Pasos de Ejecución:

# Acción Selector Tipo Objetivo
1 Click en tab Albums R.id.navigation_albums Bottom Navigation Navegación a módulo
2 Espera de carga Thread.sleep(3000) Delay fijo Mitigar cold start del backend
4 Click en primer álbum R.id.albumsRv + ViewAction personalizado RecyclerView Item Navegación a detalle
5 Verificar carátula de álbum R.id.albumCover ImageView Validar UI de detalle
6 Verificar nombre de álbum R.id.albumName TextView Validar dato principal
7 Verificar label de descripción R.id.descriptionLabel con texto R.string.description TextView Validar estructura UI
8 Click en botón back R.id.btnBack ImageButton Acción de retorno
9 Verificar lista visible nuevamente R.id.albumsRv RecyclerView Validar navegación correcta

Assertions (Verificaciones): •✅ RecyclerView de álbumes se muestra después de navegar al tab •✅ Carátula del álbum es visible en el detalle •✅ Nombre del álbum es visible en el detalle •✅ Label "Description" está presente con el texto correcto •✅ RecyclerView de álbumes se muestra nuevamente tras presionar back

Cobertura Funcional: •Navegación entre pantallas (lista ↔ detalle) •Carga de datos desde API (con tolerancia a cold start) •Renderizado de componentes UI del detalle •Botón de regreso funcional

Riesgos Mitigados: •Backend en cold start (Render): espera de 3 segundos •Race conditions de carga asíncrona

⚠️ **GitHub.com Fallback** ⚠️