Комментарии (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 с автоматическим запуском тестов