Мобильные приложения должны работать надёжно в различных сетевых условиях. Тестирование медленных соединений, прерывистой связи и offline сценариев обеспечивает надёжный пользовательский опыт. Надёжность сети напрямую влияет на производительность мобильных приложений, делая симуляцию условий необходимой для QA.
Android Симуляция Сети
Используя OkHttp Interceptors
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 {
// Симулировать задержку
if (delayMs > 0) {
Thread.sleep(delayMs)
}
// Симулировать потерю пакетов
if (Random.nextDouble() < packetLossRate) {
throw SocketTimeoutException("Симулированная потеря пакетов")
}
return chain.proceed(chain.request())
}
}
// Использование
val client = OkHttpClient.Builder()
.addInterceptor(
NetworkConditionInterceptor(
delayMs = 500,
packetLossRate = 0.1,
bandwidthBytesPerSecond = 128_000
)
)
.build()
Тестирование Различных Условий
@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)
}
Тестирование Offline Режима
Тестирование сетевых условий критически важно для мобильного тестирования в 2025, где iOS и Android приложения сталкиваются с разнообразными сценариями подключения.
@Test
fun testOfflineDataAccess() = runTest {
val offlineClient = OkHttpClient.Builder()
.addInterceptor { chain ->
throw UnknownHostException("Нет доступной сети")
}
.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 = "Тестовый Пользователь")
syncManager.queueCreateUser(newUser)
val pending = syncManager.getPendingOperations()
assertEquals(1, pending.size)
syncManager.setNetworkAvailable(true)
delay(1000)
assertEquals(0, syncManager.getPendingOperations().size)
}
Реализация offline-first паттернов требует стратегии кэширования API для мобильных приложений, обеспечивая доступность данных независимо от сетевого состояния.
Логика Повторов
Тестирование механизмов повторов при плохих сетевых условиях необходимо для тестирования производительности API, обеспечивая устойчивость к временным сбоям.
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("Превышено максимальное число повторов")
}
}
@Test
fun testRetryLogic() = runTest {
var attemptCount = 0
val client = OkHttpClient.Builder()
.addInterceptor { chain ->
attemptCount++
if (attemptCount < 3) {
throw SocketTimeoutException("Симулированный сбой")
}
chain.proceed(chain.request())
}
.addInterceptor(RetryInterceptor(maxRetries = 3))
.build()
val response = client.newCall(request).execute()
assertEquals(3, attemptCount)
assertTrue(response.isSuccessful)
}
Лучшие Практики
- Тестируйте с реалистичными сетевыми профилями - 3G, 4G, WiFi
- Реализуйте retry логику с экспоненциальным backoff - Обработка временных сбоев
- Используйте offline-first архитектуру - Кэшируйте данные локально
- Тестируйте сетевые переходы - WiFi ↔ cellular, online ↔ offline
- Мониторьте производительность сети - Отслеживайте latency, throughput
Заключение
Тестирование сетевых условий обеспечивает:
- Graceful деградацию на медленных сетях
- Offline функциональность
- Правильные механизмы retry
- Согласованность данных в сетевых состояниях
Тестирование различных сетевых условий предотвращает плохой пользовательский опыт и потерю данных.