Las aplicaciones móviles deben funcionar confiablemente en varias condiciones de red. Probar conexiones lentas, conectividad intermitente y escenarios offline asegura experiencias de usuario robustas. La confiabilidad de red impacta directamente el rendimiento de aplicaciones móviles, haciendo la simulación de condiciones esencial para QA.
Android Simulación de Red
Usando Interceptores OkHttp
class NetworkConditionInterceptor(
private val delayMs: Long = 0,
private val packetLossRate: Double = 0.0,
private val bandwidthBytesPerSecond: Long = Long.MAX_VALUE
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
// Simular latencia
if (delayMs > 0) {
Thread.sleep(delayMs)
}
// Simular pérdida de paquetes
if (Random.nextDouble() < packetLossRate) {
throw SocketTimeoutException("Pérdida de paquetes simulada")
}
return chain.proceed(chain.request())
}
}
// Uso
val client = OkHttpClient.Builder()
.addInterceptor(
NetworkConditionInterceptor(
delayMs = 500,
packetLossRate = 0.1,
bandwidthBytesPerSecond = 128_000
)
)
.build()
Testing Diferentes Condiciones
@Test
fun testSlowConnection() = runTest {
val slowClient = OkHttpClient.Builder()
.addInterceptor(NetworkConditionInterceptor(
delayMs = 2000,
bandwidthBytesPerSecond = 50_000
))
.build()
val startTime = System.currentTimeMillis()
val response = apiService.getUsers()
val duration = System.currentTimeMillis() - startTime
assertTrue(duration >= 2000)
}
@Test
fun testPacketLoss() = runTest {
val unreliableClient = OkHttpClient.Builder()
.addInterceptor(NetworkConditionInterceptor(
packetLossRate = 0.5
))
.build()
var failureCount = 0
repeat(100) {
try {
apiService.getUsers()
} catch (e: SocketTimeoutException) {
failureCount++
}
}
assertTrue(failureCount in 40..60)
}
Testing Modo Offline
El testing de condiciones de red es crucial para testing móvil en 2025, donde apps iOS y Android enfrentan diversos escenarios de conectividad.
@Test
fun testOfflineDataAccess() = runTest {
val offlineClient = OkHttpClient.Builder()
.addInterceptor { chain ->
throw UnknownHostException("Sin red disponible")
}
.build()
val repository = UserRepository(offlineClient)
val users = repository.getUsers()
assertNotNull(users)
verify { localDatabase.getUsers() }
}
@Test
fun testOfflineWriteQueueing() = runTest {
syncManager.setNetworkAvailable(false)
val newUser = User(id = "123", name = "Usuario Test")
syncManager.queueCreateUser(newUser)
val pending = syncManager.getPendingOperations()
assertEquals(1, pending.size)
syncManager.setNetworkAvailable(true)
delay(1000)
assertEquals(0, syncManager.getPendingOperations().size)
}
Implementar patrones offline-first requiere estrategia de caching API para móviles, asegurando disponibilidad de datos independientemente del estado de red.
Lógica de Retry
Probar mecanismos de retry bajo condiciones de red pobres es esencial para testing de rendimiento API, asegurando resiliencia contra fallos transitorios.
class RetryInterceptor(
private val maxRetries: Int = 3,
private val initialDelay: Long = 1000
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var attempt = 0
var delay = initialDelay
while (attempt <= maxRetries) {
try {
return chain.proceed(chain.request())
} catch (e: IOException) {
attempt++
if (attempt > maxRetries) throw e
Thread.sleep(delay)
delay *= 2
}
}
throw IOException("Reintentos máximos excedidos")
}
}
@Test
fun testRetryLogic() = runTest {
var attemptCount = 0
val client = OkHttpClient.Builder()
.addInterceptor { chain ->
attemptCount++
if (attemptCount < 3) {
throw SocketTimeoutException("Fallo simulado")
}
chain.proceed(chain.request())
}
.addInterceptor(RetryInterceptor(maxRetries = 3))
.build()
val response = client.newCall(request).execute()
assertEquals(3, attemptCount)
assertTrue(response.isSuccessful)
}
Mejores Prácticas
- Prueba con perfiles de red realistas - 3G, 4G, WiFi
- Implementa lógica retry con backoff exponencial - Maneja fallos transitorios
- Usa arquitectura offline-first - Cachea datos localmente
- Prueba transiciones de red - WiFi ↔ celular, online ↔ offline
- Monitorea rendimiento de red - Rastrea latencia, throughput
Conclusión
El testing de condiciones de red asegura:
- Degradación graceful en redes lentas
- Funcionalidad offline
- Mecanismos de retry apropiados
- Consistencia de datos en estados de red
Probar varias condiciones de red previene experiencias de usuario pobres y pérdida de datos.