Las pruebas de UI verifican la corrección de la visualización e interacción de los elementos de la interfaz de usuario de una aplicación móvil: botones, campos de texto, listas y componentes de navegación. A diferencia de las pruebas unitarias que verifican la lógica de negocio, las pruebas de UI emulan acciones del usuario: toques, deslizamientos, ingreso de texto y verifican la respuesta de la interfaz. Según un estudio de Android Developers, 2024, las pruebas de UI cubren el 70% de los escenarios críticos de usuario y permiten detectar defectos de maquetación que no son accesibles para las comprobaciones lógicas.
Puntos clave
Las pruebas de UI son un tipo de verificación automatizada en el que el código de prueba interactúa con la interfaz gráfica de la aplicación de la misma manera que lo haría un usuario real. La prueba encuentra un elemento en la pantalla — un botón, campo de texto, lista — realiza una acción sobre él y verifica la respuesta esperada de la interfaz. Por ejemplo, después de ingresar una contraseña incorrecta, una prueba de UI verifica que aparezca en la pantalla un mensaje de error con el texto correcto.
La principal diferencia entre las pruebas de UI y otros tipos de automatización es que funcionan a través de la capa de accesibilidad del sistema operativo, no a través de las API internas de la aplicación. Esto significa que las pruebas de UI ven la interfaz exactamente como la verían un usuario y un lector de pantalla. Gracias a esto, las pruebas de UI verifican no solo la funcionalidad, sino también la accesibilidad de los elementos: el cumplimiento de los requisitos WCAG.
Según la encuesta JetBrains Developer Ecosystem 2023, el 58% de los equipos móviles utilizan pruebas de UI en su pipeline de CI/CD. La cobertura media de pruebas de UI en proyectos comerciales es del 30–40% de las pantallas de la aplicación. Los proyectos con pruebas de UI reciben un 25% menos de reseñas negativas en las tiendas de aplicaciones relacionadas con fallos de interfaz.
La principal diferencia entre las pruebas de UI y las pruebas unitarias es el nivel de abstracción. Las pruebas unitarias trabajan con clases y funciones individuales, aisladas del framework de Android o iOS. Se ejecutan en la JVM (para Android) sin iniciar un emulador y toman milisegundos. Las pruebas de UI se ejecutan en un dispositivo real o emulador, interactúan con los servicios del sistema y requieren segundos o minutos por cada escenario.
También difiere el público objetivo de las pruebas. Las pruebas de UI verifican escenarios de usuario completos: registro, realización de pedidos, búsqueda. Las pruebas unitarias cubren la lógica de negocio: cálculos, validación, transformación de datos. Una prueba de UI no verifica la corrección del cálculo de impuestos — verifica que el monto total se muestre en la pantalla. El cálculo en sí lo verifica una prueba unitaria.
Según Google Testing Blog (2020), la proporción óptima de pruebas en un proyecto sigue la regla de la pirámide de pruebas: 70% de pruebas unitarias, 20% de integración y 10% de UI. La violación de esta proporción a favor de las pruebas de UI lleva a un aumento del tiempo de ejecución y a la fragilidad del conjunto de pruebas, ya que las pruebas de UI son sensibles a los cambios en la maquetación de las pantallas.
Para Android, el framework dominante es Espresso — una biblioteca de Google integrada en AndroidX Test. Espresso se sincroniza automáticamente con el hilo de UI, esperando la finalización de animaciones y tareas en segundo plano antes de ejecutar la siguiente verificación. Para Jetpack Compose se utiliza la extensión Compose UI Test, que funciona a través de nodos semánticos en lugar de los identificadores de vista tradicionales.
Para iOS, la herramienta principal es XCUITest, que forma parte de Xcode. Las pruebas se escriben en Swift y utilizan identificadores de accesibilidad para buscar elementos. XCUITest admite la grabación de pruebas mediante la función de grabación y la integración con sistemas CI a través de xcodebuild. Para proyectos multiplataforma se utiliza Appium, basado en el protocolo WebDriver y que permite ejecutar las mismas pruebas en Android e iOS con cambios mínimos en el código.
Espresso funciona con el sistema tradicional de Vistas mediante onView e identificadores de recursos. Compose UI Test utiliza una capa semántica, lo que hace que las pruebas dependan menos de la jerarquía de vistas. Por ejemplo, la búsqueda de un botón en Espresso: onView(withId(R.id.submit)), en Compose: onNodeWithTag(“submit”). Las pruebas de Compose manejan automáticamente la recomposición y no requieren esperas explícitas de estado inactivo.
XCUITest utiliza XCUIApplication como punto de entrada. Cada elemento de la interfaz se busca mediante propiedades de accesibilidad: accessibilityIdentifier para acceso programático y accessibilityLabel para VoiceOver. El framework admite la grabación de pruebas mediante la función de grabación de Xcode: el desarrollador realiza acciones en el simulador y Xcode genera el código de prueba. Las pruebas listas se ejecutan mediante xcodebuild test.
Appium se basa en el protocolo WebDriver y admite cualquier lenguaje: Java, Python, JavaScript. Las estrategias de búsqueda de elementos incluyen id, xpath, class name y accessibility id. Appium requiere instalación del servidor y configuración de Desired Capabilities: platformName, deviceName, appPackage. Una alternativa es Maestro, que utiliza escenarios YAML y no requiere compilación de código de prueba.
Consideremos pruebas de UI para un mismo escenario — inicio de sesión en la aplicación — en tres frameworks diferentes: Espresso para Android, XCUITest para iOS y Appium para el enfoque multiplataforma. Escenario: ingresar usuario y contraseña, presionar el botón de inicio, verificar que se muestre el mensaje de bienvenida.
Una prueba en Espresso utiliza onView para buscar un elemento por su identificador y perform para ejecutar una acción. El método check con el matcher isDisplayed confirma que el elemento es visible en la pantalla.
@RunWith(AndroidJUnit4::class)
class LoginUiTest {
@Rule
@JvmField
val composeTestRule = createComposeRule()
@Test
fun login_withValidCredentials_showsWelcome() {
composeTestRule
.onNodeWithTag("emailField")
.performTextInput("user@example.com")
composeTestRule
.onNodeWithTag("passwordField")
.performTextInput("secret123")
composeTestRule
.onNodeWithTag("loginButton")
.performClick()
composeTestRule
.onNodeWithText("¡Bienvenido, Usuario!")
.assertIsDisplayed()
}
}
XCUITest utiliza XCUIApplication para acceder a los elementos de la interfaz a través de identificadores de accesibilidad. Los métodos tap() y exists proporcionan interacción y verificación.
class LoginUITests: XCTestCase {
let app = XCUIApplication()
override func setUp() {
continueAfterFailure = false
app.launch()
}
func testLogin_withValidCredentials_showsWelcome() {
app.textFields["emailField"].tap()
app.textFields["emailField"].typeText("user@example.com")
app.secureTextFields["passwordField"].tap()
app.secureTextFields["passwordField"].typeText("secret123")
app.buttons["loginButton"].tap()
XCTAssertTrue(app.staticTexts["Welcome, User!"].exists)
}
}
El primer principio — utilice identificadores de accesibilidad en lugar de etiquetas de texto para buscar elementos. El texto de un botón puede cambiar durante la localización, mientras que el identificador permanece estable. En Android, esta es la propiedad contentDescription; en iOS — accessibilityIdentifier. Este enfoque hace que las pruebas sean independientes del idioma de la interfaz y reduce los costos de mantenimiento al cambiar el copywriting.
Evite sleep() y retrasos fijos — utilice los mecanismos de espera integrados del framework. Espresso espera automáticamente la finalización de animaciones y tareas en segundo plano. XCUITest proporciona XCTAssertTrue con timeout. Las pausas explícitas hacen que las pruebas sean más lentas e inestables, especialmente en dispositivos lentos en entornos CI.
Agrupe las pruebas por criticidad: las pruebas smoke (3–5 escenarios clave) se ejecutan en cada commit, el conjunto completo de pruebas de UI se ejecuta antes del lanzamiento. Según Google Testing Blog (2022), las pruebas de UI que toman más de 30 minutos en CI reducen la frecuencia de ejecución en un 40%, disminuyendo su efectividad como herramienta de detección temprana de regresiones.
Las pruebas de UI tienen varias limitaciones. Sensibilidad a cambios en la maquetación: cambiar un identificador, jerarquía o tipo de elemento rompe la prueba incluso si la funcionalidad no ha cambiado. La solución es usar el patrón Page Object, que centraliza los selectores de elementos en clases separadas. Cuando cambia la maquetación, se corrige un solo archivo de Page Object, no decenas de pruebas.
Tiempo de ejecución: la ejecución en un dispositivo real o emulador toma de 10 a 50 veces más tiempo que una prueba unitaria. La solución es ejecutar pruebas de UI en paralelo en múltiples dispositivos mediante Firebase Test Lab o AWS Device Farm. Inestabilidad (flakiness) es un problema común en ejecuciones CI, causado por animaciones, retrasos de red o el estado del emulador. Para combatir la inestabilidad se utilizan reintentos automáticos de pruebas fallidas y análisis de estabilidad de cada escenario de prueba.
Preguntas frecuentes
Para una pantalla promedio, son suficientes 3–5 pruebas de UI: happy path, validación de errores, estado vacío, cambio de orientación y verificación de accesibilidad. Pantallas complejas con múltiples estados — formularios de pedido, configuraciones — pueden requerir de 10 a 15 pruebas para una cobertura completa de los escenarios clave.
Sí, Appium y Maestro permiten ejecutar los mismos escenarios en ambas plataformas. Sin embargo, los frameworks nativos — Espresso y XCUITest — ofrecen mejor estabilidad, velocidad y acceso a funcionalidades específicas de la plataforma que no están disponibles a través de proxies WebDriver.
Para Compose se utiliza la biblioteca Compose UI Test con comparadores semánticos: onNodeWithText, onNodeWithTag, onNodeWithContentDescription. La capa semántica de Compose abstrae la jerarquía de vistas, lo que hace que las pruebas sean menos frágiles en comparación con Espresso tradicional para el sistema de Vistas.
La ejecución básica de pruebas de UI se realiza en emuladores en CI — es rápido y económico. Se recomienda realizar la verificación final antes del lanzamiento en dispositivos físicos a través de Firebase Test Lab para tener en cuenta las características del hardware real: diferentes resoluciones, versiones del SO y rendimiento.
Utilice ejecución paralela en múltiples dispositivos, desactive las animaciones en el emulador mediante Opciones de desarrollador, construya una arquitectura de pruebas modular y ejecute el conjunto smoke en cada commit, con la ejecución de regresión completa programada o antes del lanzamiento.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también