Robolectric — що це, принципи роботи та юніт-тестування Android

Автор: IT Sectr Опубліковано: 2026-04-09 Час читання: 8 хв

Robolectric — це фреймворк для юніт-тестування Android-застосунків, який дозволяє запускати тести безпосередньо на JVM без емулятора або фізичного пристрою. Він перехоплює виклики Android SDK і надає shadow-об'єкти, що емулюють поведінку реальних компонентів. За даними Robolectric Documentation, 2025, shadow-об'єкти замінюють близько 15 тисяч класів Android API, забезпечуючи ізоляцію тестів від платформи.

Головне

  • Robolectric — фреймворк для юніт-тестування Android без емулятора, що працює на JVM
  • Shadow-об'єкти перехоплюють виклики Android SDK та емулюють поведінку системи
  • Інтеграція з JUnit 4 і 5 дозволяє використовувати стандартні тестові раннери
  • Тести виконуються за секунди, а не хвилини, як в емуляторі
  • Підтримка Jetpack Compose, фрагментів, інтентів, ContentProvider та ресурсів

Що таке Robolectric

Robolectric — це open-source фреймворк, створений у 2010 році для прискорення тестування Android-застосунків. Замість запуску на емуляторі або пристрої, Robolectric надає shadow-реалізації класів Android SDK, які працюють безпосередньо на віртуальній машині Java (JVM). Це дозволяє виконувати тисячі тестів за секунди.

Проблема, яку вирішує Robolectric

Традиційне Android-тестування вимагає запуску застосунку на емуляторі, що займає 3–10 хвилин на збірку APK, встановлення та запуск. Robolectric усуває цей крок: тести компілюються як звичайні Java/Kotlin-тести та запускаються через JUnit. Це дає цикл зворотного зв'язку в кілька секунд замість хвилин.

Підтримувані версії Android

Robolectric підтримує всі версії Android починаючи з API 16 (Android 4.1) і до останньої стабільної. Для кожної версії надається відповідний набір shadow-об'єктів, які емулюють поведінку саме тієї версії платформи, на якій тестується застосунок.

Архітектура та shadow-об'єкти

Архітектура Robolectric заснована на механізмі перехоплення викликів через підміну classloader'а. Коли тест викликає метод Android SDK, Robolectric перехоплює виклик і направляє його в shadow-об'єкт. Shadow-об'єкт — це Java-клас, який імітує реальну поведінку Android-компонента, але працює без нативної платформи.

Як працюють shadows

Shadow-об'єкти реалізують ключові методи оригінальних Android-класів. Наприклад, ShadowTextView імітує методи getText(), setText(), getCurrentTextColor() та інші. При виклику textView.setText("Привіт") shadow зберігає рядок і повертає його при виклику getText(). Це ізолює тести від реального рендерингу та системних сервісів.

Shadow-ієрархія

Robolectric підтримує більше 200 shadow-класів, що покривають основні компоненти Android SDK: Activity, Fragment, TextView, Button, RecyclerView, WebView, LocationManager, ConnectivityManager та багато інших. Shadow-об'єкти слідують тій самій ієрархії успадкування, що й оригінальні класи Android.

Встановлення та налаштування Robolectric

Встановлення Robolectric в проект Gradle вимагає додавання залежності testImplementation "org.robolectric:robolectric:4.x". Також необхідно вказати androidsdk-конфігурацію у файлі build.gradle та додати роздільну здатність android:testInstrumentationRunner. Для роботи з Robolectric не потрібен плагін android-тестів.

Базова конфігурація Gradle

Після додавання залежності потрібно сконфігурувати директорію для маніфесту, ресурсів та асетів. Robolectric автоматично знаходить AndroidManifest.xml, але може знадобитися вказати шлях вручну через @Config-анотацію або системні властивості. Для мультимодульних проєктів конфігурація задається окремо для кожного модуля.

groovy
// build.gradle — налаштування Robolectric
android {
    testOptions {
        unitTests.includeAndroidResources = true
        unitTests.all {
            systemProperty 'robolectric.dependency.dir',
                project.rootDir.absolutePath + '/build/intermediates'
        }
    }
}

dependencies {
    testImplementation 'org.robolectric:robolectric:4.13'
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
}

Анотація @Config

Анотація @Config дозволяє перевизначити параметри тесту: sdk (версія API), manifest (шлях до маніфесту), qualifiers (конфігурація екрану, мова). Це корисно для тестування поведінки застосунку на різних версіях Android, орієнтаціях екрану та локалізаціях.

Написання тестів з Robolectric

Тести Robolectric пишуться як звичайні юніт-тести з @RunWith(RobolectricTestRunner.class) для JUnit 4 або через RobolectricExtension для JUnit 5. ActivityController керує життєвим циклом Activity: create(), start(), resume(), pause(), stop(), destroy(). Це дозволяє детально тестувати кожен перехід стану.

Тестування Activity

Для тестування Activity використовується ActivityController, який послідовно проходить через стадії життєвого циклу. Доступ до Activity здійснюється через controller.get(). Всі view-компоненти доступні через findViewById, як у реальному застосунку. Shadow-об'єкти дозволяють перевірити тексти, видимість, кольори та інші атрибути в'ю.

java
@RunWith(RobolectricTestRunner.class)
@Config(sdk = BuildConfig.SDK_INT)
public class MainActivityTest {

    @Test
    public void testActivityDisplaysGreeting() {
        ActivityController<MainActivity> controller =
            Robolectric.buildActivity(MainActivity.class);
        controller.create().start().resume();

        MainActivity activity = controller.get();
        TextView greeting = activity.findViewById(R.id.greeting);
        ShadowTextView shadow = Shadows.shadowOf(greeting);

        assertEquals("Welcome!", shadow.getText());
    }
}

Тестування інтентів та навігації

Robolectric перехоплює виклики startActivity() і дозволяє перевірити відправлені інтенти через ShadowActivity. Це дає можливість тестувати навігацію: перевірити, що при натисканні на кнопку відправляється Intent з правильним Action, Data та Extra-параметрами.

java
@Test
public void testNavigationToDetails() {
    controller.create().start().resume();
    MainActivity activity = controller.get();

    activity.findViewById(R.id.detailsButton).performClick();

    ShadowActivity shadowActivity = Shadows.shadowOf(activity);
    Intent intent = shadowActivity.getNextStartedActivity();
    assertEquals(
        DetailsActivity.class.getName(),
        intent.getComponent().getClassName()
    );
}

Robolectric проти емулятора

Robolectric і емулятор вирішують різні завдання. Robolectric ідеальний для швидких юніт-тестів, перевірки логіки UI, бізнес-компонентів та репозиторіїв. Емулятор необхідний для інструментаційних тестів, перевірки інтеграції з API, тестування камери, датчиків та продуктивності.

ХарактеристикаRobolectricЕмулятор
Швидкість~5 сек на 100 тестів~5 хв на 100 тестів
ЗапускБез збірки APKПотрібна збірка APK
Реальне APIShadow-емуляціяНативний Android SDK
Out-of-the-boxТільки JUnitБудь-які фреймворки

Тестування ViewModel та Repository

Robolectric чудово підходить для тестування ViewModel, Repository та UseCase — компонентів, які використовують Android SDK, але не потребують реального UI. ViewModel тестується через звичайний JUnit-тест з RobolectricExtension, при цьому lifecycle-компоненти (LiveData, StateFlow) працюють у shadow-середовищі без моків.

Тестування LiveData

Robolectric підтримує LiveData з коробки: можна підписатися на LiveData в тесті, змінити стан через ViewModel та перевірити емітоване значення. Для асинхронних операцій використовується InstantTaskExecutorRule або runBlocking для корутин. Це позбавляє від необхідності мокати архітектурні компоненти.

kotlin
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [BuildConfig.SDK_INT])
class ProfileViewModelTest {

    private val repository = FakeUserRepository()
    private val viewModel = ProfileViewModel(repository)

    @Test
    fun `loading profile sets state to success`() = runBlocking {
        viewModel.loadProfile("user123")
        val state = viewModel.profileState.getOrAwaitValue()
        Assertions.assertTrue(state is UiState.Success)
    }
}

Кастомні Shadow-об'єкти

Якщо стандартні shadow-об'єкти Robolectric не покривають потрібний клас Android SDK, можна створити кастомний Shadow. Для цього створюється клас з анотацією @Implements(ClassName.class) та реалізуються потрібні методи з @Implementation. Кастомні shadows реєструються через @Config(shadows = [CustomShadow::class]).

Тестування ContentProvider та Resources

Robolectric підтримує тестування ContentProvider через Robolectric.buildContentProvider(). Можна перевірити CRUD-операції, запити з URI-матчингом та обробку прав доступу. Ресурси (рядки, кольори, розміри) також доступні через RuntimeEnvironment.application.resources, що дозволяє тестувати код, залежний від ресурсів.

Міграція з емулятора на Robolectric

Перехід з інструментаційних тестів на Robolectric вимагає зміни підходу. Інструментаційні тести (AndroidJUnit4) перевіряють реальну поведінку на емуляторі, Robolectric — ізольовану логіку в shadow-середовищі. Рекомендується покривати Robolectric-тестами бізнес-логіку, а інструментаційні тести залишити для інтеграційних сценаріїв.

Адаптація існуючих тестів

При міграції потрібно: замінити AndroidJUnit4 на RobolectricTestRunner, додати @Config з цільовою версією SDK, замінити ActivityTestRule на ActivityController та перенести залежності з androidTestImplementation в testImplementation. Моки (MockK, Mockito) працюють з Robolectric без змін — вони не залежать від платформи.

Обмеження при міграції

Robolectric не підтримує: тестування камери (CameraX), NFC, Bluetooth, біометрію, роботу з реальними файлами та нативними бібліотеками. Для цих сценаріїв необхідні інструментаційні тести на емуляторі. Robolectric також не відтворює реальний рендеринг — тести верстки краще виконувати через Compose Test Rule або Espresso. Однак для перевірки бізнес-логіки, навігації та станів ViewModel Robolectric повністю замінює емулятор з 10-кратним прискоренням прогону.

Сумісність з Java та Kotlin версіями

Robolectric вимагає JDK 11 або вище і сумісний з AGP (Android Gradle Plugin) від 7.0 до останньої стабільної версії. SDK-менеджер Robolectric автоматично завантажує необхідні версії Android API при першому запуску — це одноразова операція. Для CI-серверів рекомендується попередньо завантажити SDK через sdkmanager, щоб уникнути затримок при першому прогоні тестів. Оновлення Robolectric до нової версії зазвичай не вимагає змін у коді тестів, тільки оновлення номера залежності в build.gradle.

Інтеграція з MockK та Mockito

Robolectric сумісний з популярними mocking-фреймворками: MockK для Kotlin та Mockito для Java. Моки використовуються для ізоляції залежностей: репозиторіїв, API-клієнтів, SharedPreferences. Головне правило — не мокати класи Android SDK, для цього є shadow-об'єкти. Мокайте тільки шари застосунку: UseCase, Repository, DataSource та інші компоненти бізнес-логіки. Така комбінація shadow-об'єктів та моків дає максимальну гнучкість при мінімальних витратах на написання тестів.

Часто задавані питання

Чим відрізняється Robolectric від Espresso?

Espresso — це інструментаційний фреймворк, що запускається на емуляторі або пристрої. Robolectric — це юніт-фреймворк, що працює на JVM. Espresso тестує реальну поведінку, Robolectric — ізольовану логіку в shadow-середовищі. Вони доповнюють один одного.

Чи можна тестувати Jetpack Compose з Robolectric?

Так, Robolectric підтримує Jetpack Compose починаючи з версії 4.8. Тести Compose-компонентів виконуються за допомогою ComposeTestRule, аналогічно емулятору. Однак Compose-тести на Robolectric не перевіряють реальний рендеринг — тільки логіку композиції.

Як Robolectric працює з Gradle-модулями?

Robolectric підтримує мультимодульні проєкти. Кожен модуль налаштовується окремо із зазначенням свого маніфесту та ресурсів. Для модулів без UI-компонентів достатньо бібліотечного модуля без android-плагіна. У великих проєктах з десятками модулів Robolectric тести кожного модуля запускаються паралельно, що дає додатковий виграш у швидкості порівняно з послідовним прогоном на емуляторі.

Чому Robolectric може не знайти ресурси?

Проблема з ресурсами виникає, якщо в build.gradle не вказано unitTests.includeAndroidResources = true або відсутня @Config-анотація з правильним шляхом до маніфесту. Robolectric використовує скомпільовані ресурси з build/intermediates.

Як налагоджувати Robolectric-тести?

Robolectric-тести налагоджуються як звичайні Java/Kotlin-тести в Android Studio. Доступний breakpoint, step-through debug, інспекція shadow-об'єктів та їх стану. Логування вмикається через -Drobolectric.logging=debug в VM options.

Підсумки

  • Robolectric — фреймворк для швидкого юніт-тестування Android на JVM без емулятора
  • Shadow-об'єкти замінюють понад 200 класів Android SDK, емулюючи їх поведінку
  • Життєвий цикл Activity та Fragment керується через ActivityController з перевіркою станів
  • Тестування інтентів через ShadowActivity дозволяє перевіряти навігацію та передачу даних
  • Інтеграція з JUnit та Gradle не потребує додаткових інструментаційних раннерів
  • Анотація @Config задає версію API, мову, конфігурацію екрану та ресурси
  • Robolectric та Espresso доповнюють один одного: швидкі юніт-тести проти інструментаційних

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також