Cómo realizar pruebas unitarias en apps Android

Las pruebas unitarias son una parte esencial del desarrollo de software de calidad. En el mundo de Android, aseguran que cada componente individual de tu aplicación funcione correctamente antes de integrarlo con el resto del sistema. Este artículo te guiará a través del proceso de implementación de pruebas unitarias efectivas en tus proyectos Android, desde la configuración inicial hasta la escritura de pruebas complejas.
Dominar las pruebas unitarias es fundamental para reducir errores, mejorar la mantenibilidad del código y agilizar el proceso de desarrollo de tus aplicaciones Android.
¿Por qué realizar pruebas unitarias en Android?

Las pruebas unitarias ofrecen múltiples beneficios en el desarrollo de apps Android:
- Detección temprana de errores: Identifica problemas en etapas tempranas del ciclo de vida del desarrollo.
- Mejor calidad del código: Fomenta un código más limpio, modular y fácil de mantener.
- Refactorización segura: Permite realizar cambios en el código con la confianza de que las funcionalidades básicas no se verán afectadas.
- Documentación viva: Sirven como documentación del comportamiento esperado de cada componente.
- Desarrollo más rápido: A largo plazo, reduce el tiempo dedicado a depuración y corrección de errores.
«Las pruebas unitarias son la primera línea de defensa contra errores en tu código. Invertir tiempo en ellas siempre vale la pena.» – Kent Beck, Extreme Programming Explained
Configuración del entorno de pruebas
Para empezar a escribir pruebas unitarias, necesitas configurar el entorno de pruebas en tu proyecto Android. Android Studio proporciona un soporte excelente para JUnit, Mockito y otros frameworks populares.
Dependencias Gradle
Asegúrate de agregar las dependencias necesarias al archivo `build.gradle (Module: app)`:
- JUnit: El framework base para las pruebas unitarias.
- Mockito: Un framework para crear objetos simulados (mocks).
- Espresso: Framework de pruebas de IU. Aunque no es una prueba unitaria per se, es necesario para pruebas de integración UI.
- Truth: Framework de aserciones fluidas.
Aquí un ejemplo de dependencias:
dependencies {
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-core:4.11.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
testImplementation 'com.google.truth:truth:1.1.3'
}
Estructura de directorios
Android Studio crea automáticamente dos directorios para pruebas:
- `src/test/java`: Para pruebas unitarias locales que se ejecutan en la JVM.
- `src/androidTest/java`: Para pruebas instrumentadas que se ejecutan en un dispositivo Android o emulador.
Escribiendo tu primera prueba unitaria

Vamos a crear una prueba simple para una clase llamada `Calculator` que tiene un método `add`:
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}
Aquí está la prueba unitaria:
import org.junit.Test;
import static org.junit.Assert.*;
public class CalculatorTest {
@Test
public void testAdd() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
assertEquals(5, result);
}
}
Paso a paso:
- Crea una nueva clase en el directorio `src/test/java`.
- Añade la anotación `@Test` al método que contendrá la prueba.
- Crea una instancia de la clase que quieres probar.
- Ejecuta el método que quieres probar.
- Utiliza `assertEquals()` (o una aserción similar) para verificar que el resultado es el esperado.
Utilizando Mockito para simular dependencias
Mockito es una herramienta poderosa para simular dependencias externas en tus pruebas unitarias. Esto es útil cuando una clase depende de otra que es difícil de instanciar o que tiene efectos secundarios no deseados.
Ejemplo de uso de Mockito
import org.junit.Test;
import org.mockito.Mockito;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class MyClassTest {
@Test
public void testMyMethod() {
// Crea un mock de MyDependency
MyDependency dependency = Mockito.mock(MyDependency.class);
// Define el comportamiento del mock
when(dependency.getValue()).thenReturn(10);
// Crea una instancia de MyClass con el mock
MyClass myClass = new MyClass(dependency);
// Ejecuta el método a probar
int result = myClass.myMethod();
// Verifica que el resultado es el esperado
assertEquals(20, result);
// Verifica que el método getValue() fue llamado
verify(dependency).getValue();
}
}
class MyClass {
private MyDependency dependency;
public MyClass(MyDependency dependency) {
this.dependency = dependency;
}
public int myMethod() {
return dependency.getValue() + 10;
}
}
class MyDependency {
public int getValue() {
return 0;
}
}
En este ejemplo, `MyDependency` es simulada con Mockito. Esto permite controlar el valor retornado por `getValue()` y verificar que el método fue llamado durante la ejecución de la prueba.
Buenas prácticas para pruebas unitarias

Aquí hay algunas prácticas recomendadas para escribir pruebas unitarias efectivas:
- Escribe pruebas antes de escribir el código: Esto te ayuda a definir claramente los requisitos y a diseñar un código más testable (TDD – Test-Driven Development).
- Cubre todos los casos de uso: Asegúrate de que tus pruebas cubran todos los escenarios posibles, incluyendo casos positivos, negativos y de borde.
- Mantén las pruebas independientes: Cada prueba debe ser independiente de las demás. Esto evita que una falla en una prueba afecte a otras.
- Utiliza nombres descriptivos: Los nombres de las pruebas deben indicar claramente qué se está probando.
- Mantén las pruebas simples y concisas: Evita pruebas complejas que sean difíciles de entender y mantener.
- Ejecuta las pruebas con frecuencia: Integra las pruebas en tu proceso de desarrollo para detectar errores rápidamente.
Ejemplo de tabla con información relevante
Tabla comparativa de frameworks de testing en Android:
| Framework | Tipo de Prueba | Ventajas | Desventajas |
|---|---|---|---|
| JUnit | Unitaria | Sencillo, ampliamente utilizado, estándar. | Limitado para pruebas complejas. |
| Mockito | Unitaria (Mocking) | Facilita el mocking de dependencias, aísla el código. | Requiere aprender la sintaxis, puede complicar pruebas. |
| Espresso | IU (Instrumentada) | Pruebas UI robustas, sincronización automática. | Más lento, requiere un emulador/dispositivo. |
| Truth | Aserciones | Aserciones más legibles y expresivas. | Requiere una dependencia adicional. |
| Robolectric | Unitaria | Permite ejecutar pruebas en la JVM sin emulador. | Puede no simular todos los aspectos del entorno Android. |
| AssertJ | Aserciones | Aserciones fluidas y encadenables. | Similar a Truth, elección según preferencia. |
| UI Automator | IU (Instrumentada) | Pruebas UI cross-app y system-level. | Curva de aprendizaje más pronunciada. |
| KotlinTest | Unitaria | Especialmente diseñado para Kotlin, flexible. | Requiere estar usando Kotlin. |
| PowerMock | Unitaria (Mocking) | Permite mockear clases finales y métodos estáticos. | Uso con cautela, puede indicar problemas de diseño. |
| TestNG | Unitaria | Alternativa a JUnit, funcionalidades extras. | Menos popular que JUnit en Android. |
Conclusión

Las pruebas unitarias son una inversión valiosa para el desarrollo de aplicaciones Android. Al adoptar buenas prácticas de pruebas y utilizar las herramientas adecuadas, puedes mejorar significativamente la calidad, la mantenibilidad y la estabilidad de tu código. Empieza a escribir pruebas unitarias hoy mismo y observa cómo tu proceso de desarrollo se transforma.








