← Назад к вопросам

Какие знаешь способы тестирования TEA?

2.0 Middle🔥 21 комментариев
#Архитектура и паттерны#Тестирование

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Способы тестирования TEA (Test Environment Abstraction)

TEA (Test Environment Abstraction) — это архитектурный подход в Android-разработке, который **абстрагирует зависимости от внешнего окружения** (сеть, БД, файловая система, системные сервисы) для целей тестирования. Это позволяет изолировать юнит-тесты от нестабильных или медленных внешних ресурсов. Вот ключевые способы тестирования в парадигме TEA:

1. Внедрение зависимостей (Dependency Injection)

Использование DI-фреймворков (Dagger/Hilt, Koin) или ручного внедрения для замены реальных реализаций на тестовые дублеры (test doubles).

// Реальная зависимость
class NetworkRepository(
    private val apiService: ApiService, // Интерфейс!
    private val database: AppDatabase
)

// Тестовая версия
@Test
fun testRepository() {
    val mockApi = mock<ApiService> {
        on { fetchData() } doReturn Flow.just(testData)
    }
    val fakeDb = FakeDatabase() // In-memory реализация
    val repo = NetworkRepository(mockApi, fakeDb)
    // Тестируем repo
}

2. Использование Test Doubles

  • Моки (Mockito, MockK): Объекты с запрограммированным поведением и проверкой вызовов.
  • Стабы (Stubs): Упрощённые реализации, возвращающие предопределённые данные.
  • Фейки (Fakes): Рабочие упрощённые реализации (например, in-memory база данных).
  • Спаи (Spies): Частичные моки, обёртывающие реальные объекты.
// Пример с MockK
@Test
fun testWithMockK() {
    val mockService = mockk<LocationService>()
    every { mockService.getCurrentLocation() } returns Location("Test", 0.0, 0.0)
    
    val viewModel = LocationViewModel(mockService)
    viewModel.loadLocation()
    
    verify { mockService.getCurrentLocation() }
}

3. Абстракция через интерфейсы

Ключевой принцип TEA — программирование на интерфейсах, а не на конкретных реализациях.

interface ConnectivityChecker {
    fun isOnline(): Boolean
}

class RealConnectivityChecker(
    private val context: Context
) : ConnectivityChecker {
    override fun isOnline(): Boolean {
        // Реальная проверка сети
    }
}

class FakeConnectivityChecker(
    private var isOnlineState: Boolean
) : ConnectivityChecker {
    override fun isOnline(): Boolean = isOnlineState
}

4. Архитектурные паттерны

  • MVVM/MVI с Repository Pattern: ViewModel зависит от абстракций Repository.
  • Clean Architecture: Чёткое разделение на слои с инверсией зависимостей.
  • MVI (Model-View-Intent): Предсказуемое состояние, удобное для тестирования.

5. Тестовые конфигурации DI

Настройка отдельных тестовых компонентов и модулей в Dagger/Hilt.

// Основной модуль
@Module
@InstallIn(SingletonComponent::class)
class NetworkModule {
    @Provides
    fun provideApiService(): ApiService = RetrofitApiService()
}

// Тестовый модуль
@Module
@TestInstallIn(components = [SingletonComponent::class])
class TestNetworkModule {
    @Provides
    fun provideApiService(): ApiService = FakeApiService()
}

6. Тестовые Rule и Hilt-расширения

Использование JUnit Rules и Hilt-тестирования для управления жизненным циклом тестов.

@HiltAndroidTest
class MyInstrumentedTest {
    @get:Rule
    val hiltRule = HiltAndroidRule(this)
    
    @Before
    fun init() {
        hiltRule.inject()
    }
}

7. Тестирование с Coroutines/Flow

Специальные утилиты для тестирования асинхронного кода.

class ViewModelTest {
    @Test
    fun testFlowData() = runTest { // TestCoroutineScope
        val testData = listOf("A", "B", "C")
        val repository = FakeRepository(testData)
        val viewModel = MyViewModel(repository)
        
        val results = mutableListOf<String>()
        viewModel.data.collect { results.add(it) }
        
        assertEquals(testData, results)
    }
}

8. Паттерн "Ports and Adapters" (Hex Architecture)

Внешние зависимости подключаются через "порты" (интерфейсы) и "адаптеры" (реализации).

Практические преимущества TEA:

  • Изоляция тестов: Тесты не зависят от сети, БД или других сервисов.
  • Скорость: Моки и фейки работают в памяти, без I/O операций.
  • Детерминированность: Предсказуемое поведение тестовых дублёров.
  • Покрытие сценариев: Легко эмулировать ошибки сети, исключения, пограничные случаи.
  • Снижение связанности: Код становится более модульным и поддерживаемым.

Ограничения и дополнения:

  • Интеграционные тесты: TEA не заменяет полностью интеграционные и UI-тесты (Espresso).
  • Over-mocking: Риск чрезмерного использования моков, что делает тесты хрупкими.
  • Реальные сценарии: Критические пути стоит проверять с реальными зависимостями.

Итог: TEA — это мощная методология, которая при правильном применении значительно повышает надежность, скорость разработки и качество кода за счёт строгого разделения логики приложения и внешнего окружения. Ключ успеха — сбалансированное сочетание юнит-тестов с TEA, интеграционных и UI-тестов.

Какие знаешь способы тестирования TEA? | PrepBro