Pruebas unitarias con JUnit
Escriba pruebas unitarias rápidas y fiables con JUnit 4. Use @Test, @Before, @After y aserciones; pruebe LiveData con InstantTaskExecutorRule y corrutinas con runTest.
Pruebas unitarias con JUnit es una lección gratuita de Android Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Android Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Android Academy incluye 4 lecciones en total.
¿Por qué escribir pruebas?
Las pruebas no son un lujo: son su red de seguridad:
- Detectan errores antes que los usuarios
- Permiten refactorizar con confianza (si las pruebas pasan, nada se ha roto)
- Documentan el comportamiento previsto
- Evitan regresiones al añadir funcionalidades
El código bien probado también suele estar mejor diseñado: si es difícil de probar, probablemente el diseño está demasiado acoplado.
Tipos de pruebas de Android
Dos categorías:
- Pruebas unitarias (carpeta
test/) — se ejecutan en la JVM, sin necesidad de un dispositivo. Son rápidas. Prueban lógica común de Kotlin/Java. - Pruebas instrumentadas (carpeta
androidTest/) — se ejecutan en un dispositivo o emulador. Son más lentas. Prueban código específico de Android (base de datos Room, interfaz de usuario).
Prefiera las pruebas unitarias para la lógica de negocio. Use pruebas instrumentadas solo cuando deba interactuar con las API de Android.
Configuración de JUnit 4
JUnit 4 se incluye de forma predeterminada en los proyectos de Android. Añada lo siguiente a app/build.gradle:
// app/build.gradle:
dependencies {
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3'
testImplementation 'androidx.arch.core:core-testing:2.2.0' // for LiveData
}Su primera prueba de JUnit
Cree una clase en src/test/java/ y anote los métodos de prueba con @Test:
import org.junit.Test
import org.junit.Assert.*
class CalculatorTest {
private val calc = Calculator()
@Test
fun `addition returns correct sum`() {
val result = calc.add(2, 3)
assertEquals(5, result)
}
@Test
fun `division by zero throws exception`() {
assertThrows(ArithmeticException::class.java) {
calc.divide(10, 0)
}
}
}@Before y @After
Use anotaciones del ciclo de vida para configurar y desmontar el estado alrededor de cada prueba:
class UserRepositoryTest {
private lateinit var repo: UserRepository
private lateinit var fakeDao: FakeUserDao
@Before
fun setUp() {
fakeDao = FakeUserDao() // fresh instance before each test
repo = UserRepository(fakeDao)
}
@After
fun tearDown() {
fakeDao.clear() // clean up after each test
}
@Test
fun `getUsers returns all users`() {
fakeDao.insert(User(1, "Alice"))
fakeDao.insert(User(2, "Bob"))
assertEquals(2, repo.getUsers().size)
}
}Aserciones habituales
JUnit proporciona métodos de aserción en Assert.*:
// Equality:
assertEquals(expected, actual)
assertNotEquals(unexpected, actual)
// Null:
assertNull(value)
assertNotNull(value)
// Boolean:
assertTrue(condition)
assertFalse(condition)
// Same object reference:
assertSame(expected, actual)
// Custom message on failure:
assertEquals("User ID should be 1", 1, user.id)
// Exception:
assertThrows(IllegalArgumentException::class.java) {
User(id = -1, name = "")
}Pruebas de un ViewModel
Para probar LiveData, añada InstantTaskExecutorRule para que LiveData publique de forma síncrona:
class UserViewModelTest {
@get:Rule
val instantTaskRule = InstantTaskExecutorRule()
private val fakeRepo = FakeUserRepository()
private lateinit var viewModel: UserViewModel
@Before
fun setUp() {
viewModel = UserViewModel(fakeRepo)
}
@Test
fun `users are loaded on init`() {
fakeRepo.usersToReturn = listOf(User(1, "Alice"), User(2, "Bob"))
viewModel.loadUsers()
val result = viewModel.users.value
assertNotNull(result)
assertEquals(2, result?.size)
}
}Pruebas de corrutinas
Use TestCoroutineDispatcher / StandardTestDispatcher para controlar la ejecución de corrutinas en las pruebas:
class SyncWorkerTest {
@get:Rule
val instantTaskRule = InstantTaskExecutorRule()
private val testDispatcher = StandardTestDispatcher()
@Before
fun setUp() {
Dispatchers.setMain(testDispatcher)
}
@After
fun tearDown() {
Dispatchers.resetMain()
}
@Test
fun `sync completes successfully`() = runTest {
val repo = FakeRepository()
val worker = SyncUseCase(repo, testDispatcher)
val result = worker.run()
assertTrue(result.isSuccess)
}
}Fake frente a Mock
Dos estrategias para reemplazar dependencias reales en las pruebas:
- Fake — una implementación funcional diseñada para las pruebas (por ejemplo, una lista en memoria en lugar de una base de datos real). Es fácil de escribir y leer, y no requiere ninguna biblioteca.
- Mock — un objeto simulado generado automáticamente que registra las llamadas y permite verificar las interacciones (Mockito, MockK). Es más potente, pero puede volverse frágil si se usa en exceso.
Prefiera los Fakes para casos sencillos; use Mocks cuando necesite verificar llamadas a métodos.
Cómo escribir un Fake
Un Fake implementa la misma interfaz que la clase real, pero utiliza almacenamiento en memoria:
interface UserDao {
fun getAll(): List<User>
fun insert(user: User)
}
class FakeUserDao : UserDao {
private val storage = mutableListOf<User>()
override fun getAll(): List<User> = storage.toList()
override fun insert(user: User) { storage.add(user) }
fun clear() { storage.clear() }
}Convención para nombrar pruebas
Los buenos nombres de prueba describen qué se está probando y cuál es el resultado esperado. Use nombres de funciones entre comillas invertidas en Kotlin para obtener descripciones legibles:
`getUsers returns empty list when no users exist``login throws exception when password is blank``add returns correct sum for negative numbers`
Patrón: `subject does X when Y`
Comprobación rápida
¿Cuál es la finalidad de @Before en una clase de prueba de JUnit?
Repaso: pruebas unitarias con JUnit
Las aplicaciones fiables son aplicaciones probadas:
- Las pruebas unitarias se colocan en
src/test/y se ejecutan en la JVM; son rápidas - Anótelas con
@Testy useassertEquals,assertTrueyassertThrows @Before/@Afterpara la configuración y el desmontajeInstantTaskExecutorRulepara probar LiveData de forma síncronarunTest+StandardTestDispatcherpara probar corrutinas- Prefiera los Fakes a los Mocks para sustituciones sencillas
A continuación: simulación con Mockito para verificar interacciones.
Preguntas frecuentes
¿La lección «Pruebas unitarias con JUnit» es gratis?
Sí — el texto completo de «Pruebas unitarias con JUnit» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Android Academy, actualiza a CoddyKit PRO. El curso de Android Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Pruebas unitarias con JUnit»?
Escriba pruebas unitarias rápidas y fiables con JUnit 4. Use @Test, @Before, @After y aserciones; pruebe LiveData con InstantTaskExecutorRule y corrutinas con runTest. Practicas Android Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Android Academy?
No se requiere experiencia previa. Android Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «Pruebas unitarias con JUnit»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Android Academy?
Sí. Cada lección de Android Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Pruebas unitarias con JUnit
- Mocking con Mockito
- Pruebas de interfaz con Espresso
- Depuración y profiling