Las condiciones de red impactan profundamente la experiencia del usuario de maneras que los entornos de desarrollo nunca replican. Según un estudio de Google, el 53% de los usuarios móviles abandonan sitios que tardan más de 3 segundos en cargar. Según investigación de Akamai, las páginas que experimentan incluso breves interrupciones de red ven tasas de rebote un 40% más altas. Probar bajo condiciones de red realistas no es opcional para equipos que apuntan a mercados globales: debes verificar cómo se comporta tu aplicación a diferentes anchos de banda (2G, 3G, 4G, WiFi), latencias y tasas de pérdida de paquetes. Esta guía cubre herramientas de simulación de condiciones de red.

TL;DR: El testing de condiciones de red simula conectividad del mundo real para apps web y móviles. Usa Chrome DevTools para testing en navegador, tc netem (Linux) para simulación a nivel OS y Charles Proxy/Proxyman para throttling de tráfico móvil. Prueba mínimamente: perfiles Fast 3G, Slow 3G y 2G.

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)
}

“Most teams test their apps on localhost with perfect network conditions and wonder why mobile users complain. Network simulation is not optional — it’s the only way to know how your app actually performs in the real world.” — Yuri Kan, Senior QA Lead

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

  1. Prueba con perfiles de red realistas - 3G, 4G, WiFi
  2. Implementa lógica retry con backoff exponencial - Maneja fallos transitorios
  3. Usa arquitectura offline-first - Cachea datos localmente
  4. Prueba transiciones de red - WiFi ↔ celular, online ↔ offline
  5. 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.

Ver También

Recursos Oficiales

FAQ

¿Qué perfiles de red debo probar?

Perfiles estándar: WiFi (50+ Mbps, 5ms latencia), Fast 4G/LTE (10 Mbps, 20ms), Regular 4G (4 Mbps, 30ms), Fast 3G (1.5 Mbps, 40ms), Slow 3G (400 Kbps, 400ms), 2G (250 Kbps, 750ms) y Offline. Prioriza perfiles que coincidan con la demografía de tus usuarios.

¿Cómo simulo condiciones de red para testing móvil?

Para iOS: usa Xcode Network Link Conditioner. Para Android: usa opciones de desarrollador > Simular condiciones de red, o tc netem vía adb en dispositivos rooteados. Para ambas plataformas: usa una herramienta proxy como Charles Proxy para limitar todo el tráfico.

¿Cómo pruebo el modo offline y la degradación elegante?

Prueba: offline completo, transición de online a offline durante una operación, conectividad parcial (pérdida de paquetes intermitente) y fallos de DNS. Verifica: los datos en caché se sirven offline, las operaciones pendientes se encolan y se reanudan al reconectarse.

¿Cómo simulo pérdida de paquetes en testing?

Linux tc netem: ’tc qdisc add dev eth0 root netem loss 5%’ simula 5% de pérdida. El perfil personalizado de Chrome DevTools soporta simulación de pérdida de paquetes. La configuración de Charles Proxy Throttle incluye pérdida de paquetes.

See Also