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

Какие знаешь виды автотестов?

1.0 Junior🔥 161 комментариев
#Тестирование

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

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

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

Виды автотестов для Android

Автотестирование критично для качества приложений. Существует несколько уровней тестирования с разными целями и скоростью выполнения.

1. Unit тесты (Быстрые, изолированные)

Тестируют отдельные функции и классы без зависимостей:

// build.gradle
testImplementation "junit:junit:4.13.2"
testImplementation "io.mockk:mockk:1.13.5"
testImplementation "org.assertj:assertj-core:3.24.1"

// UserRepositoryTest.kt
class UserRepositoryTest {
    private val mockUserApi = mockk<UserApi>()
    private val repository = UserRepository(mockUserApi)
    
    @Test
    fun `should return user when API call succeeds`() {
        // Arrange (подготовка)
        val expectedUser = User(id = "1", name = "John")
        coEvery { mockUserApi.getUser("1") } returns expectedUser
        
        // Act (выполнение)
        val result = repository.getUser("1")
        
        // Assert (проверка)
        assertThat(result).isEqualTo(expectedUser)
        coVerify { mockUserApi.getUser("1") }
    }
    
    @Test
    fun `should throw exception when API fails`() {
        // Arrange
        coEvery { mockUserApi.getUser("1") } throws RuntimeException("API Error")
        
        // Act & Assert
        assertThrows<RuntimeException> {
            repository.getUser("1")
        }
    }
}

Характеристики:

  • Выполняются на JVM (очень быстро)
  • Используют моки для зависимостей
  • Тестируют business logic в изоляции
  • 70% тестов должны быть Unit тесты

2. Integration тесты (Средней скорости)

Тестируют взаимодействие нескольких компонентов:

// Database + Repository интеграционный тест
@RunWith(AndroidJUnit4::class)
class UserRepositoryIntegrationTest {
    @get:Rule
    val instantExecutorRule = InstantTaskExecutorRule()
    
    @get:Rule
    val databaseRule = TestDatabaseRule()
    
    private val userDao = databaseRule.db.userDao()
    private val mockApi = mockk<UserApi>()
    private val repository = UserRepository(userDao, mockApi)
    
    @Test
    fun `should save and retrieve user from database`() {
        val user = User(id = "1", name = "John")
        userDao.insert(user)
        
        val retrieved = userDao.getUser("1")
        assertThat(retrieved).isEqualTo(user)
    }
}

Характеристики:

  • Используют реальные компоненты (БД, API моки)
  • Медленнее unit тестов
  • Тестируют workflow между слоями
  • 20% тестов могут быть integration

3. UI/Instrumentation тесты (Медленные)

Тестируют пользовательский интерфейс и взаимодействия:

// Espresso для XML
@RunWith(AndroidJUnit4::class)
class LoginScreenTest {
    @get:Rule
    val activityRule = ActivityScenarioRule(LoginActivity::class.java)
    
    @Test
    fun `should show error when login fails`() {
        // Arrange
        onView(withId(R.id.email)).perform(typeText("test@example.com"))
        onView(withId(R.id.password)).perform(typeText("wrong_password"))
        
        // Act
        onView(withId(R.id.loginButton)).perform(click())
        
        // Assert
        onView(withText("Invalid credentials")).check(matches(isDisplayed()))
    }
}

// Jetpack Compose тесты
@RunWith(AndroidJUnit4::class)
class LoginScreenComposeTest {
    @get:Rule
    val composeRule = createComposeRule()
    
    @Test
    fun `should display login form`() {
        composeRule.setContent {
            LoginScreen()
        }
        
        composeRule.onNodeWithText("Email").assertIsDisplayed()
        composeRule.onNodeWithText("Password").assertIsDisplayed()
    }
}

Характеристики:

  • Выполняются на реальном устройстве или эмуляторе
  • Самые медленные
  • Тестируют UI поведение
  • 10% тестов могут быть UI тесты

4. E2E тесты (End-to-End)

Полный пользовательский сценарий от начала до конца:

@RunWith(AndroidJUnit4::class)
class LoginFlowE2ETest {
    @get:Rule
    val activityRule = ActivityScenarioRule(MainActivity::class.java)
    
    @Test
    fun `complete login and navigation flow`() {
        // Шаг 1: Переход на экран входа
        onView(withId(R.id.loginButton)).perform(click())
        
        // Шаг 2: Вход в систему
        onView(withId(R.id.email)).perform(typeText("user@example.com"))
        onView(withId(R.id.password)).perform(typeText("password123"))
        onView(withId(R.id.submitButton)).perform(click())
        
        // Шаг 3: Проверка что мы на главном экране
        Thread.sleep(2000)  // Ждём загрузки
        onView(withText("Welcome, User")).check(matches(isDisplayed()))
        
        // Шаг 4: Открыть профиль
        onView(withId(R.id.profileIcon)).perform(click())
        onView(withText("user@example.com")).check(matches(isDisplayed()))
    }
}

5. Performance тесты (Benchmarking)

Тестирование производительности:

@RunWith(AndroidJUnit4::class)
class PerformanceTest {
    @get:Rule
    val benchmarkRule = BenchmarkRule()
    
    @Test
    fun `measure list scrolling performance`() {
        benchmarkRule.measureRepeated {
            // Код что измеряем
            val list = (1..10000).toList()
            list.filter { it % 2 == 0 }.map { it * 2 }
        }
    }
}

6. Snapshot тесты (Регрессионное тестирование)

Проверяют что UI не изменился неожиданно:

@RunWith(AndroidJUnit4::class)
class SnapshotTest {
    @get:Rule
    val composeRule = createComposeRule()
    
    @Test
    fun `login screen snapshot`() {
        composeRule.setContent {
            LoginScreen()
        }
        // Сравнивает с сохранённым снимком
        // Если UI изменился, тест падает
    }
}

7. Contract тесты (Для микросервисов)

Тестируют контракт между client и API:

// Проверяем что API возвращает ожидаемый формат
@Test
fun `user endpoint should return correct format`() {
    val mockServer = MockWebServer()
    mockServer.enqueue(MockResponse()
        .setBody("""
            {
                "id": "123",
                "name": "John",
                "email": "john@example.com"
            }
        """)
    )
    
    // Парсим и проверяем
    val user = gson.fromJson(mockServer.takeRequest().body, User::class.java)
    assertThat(user.id).isNotEmpty()
}

Пирамида тестирования

        /\
       /  \  E2E (Медленно, дорого)
      /____\
     /      \
    /  UI   \  Integration/UI (Средне)
   /________\
  /          \
 / Unit Tests \ (Быстро, дешево)
/______________\

Рекомендуемое распределение:

  • 70% Unit тесты
  • 20% Integration тесты
  • 10% E2E/UI тесты

Best Practices

  • Писать тесты ДО кода (TDD)
  • Каждый тест проверяет одно (Single Responsibility)
  • Независимые тесты — порядок выполнения не важен
  • Быстрые unit тесты в watch mode
  • Моки для внешних зависимостей (API, БД)
  • Реальные компоненты для integration тестов
  • Минимум UI тестов — они медленные
  • Coverage 90%+ для production code
  • CI/CD pipeline с автоматическим запуском тестов