Robolectric — какво е, принципи на работа и unit тестване на Android

Автор: IT Sectr Публикувано: 2026-04-09 Време за четене: 8 мин

Robolectric е рамка за unit тестване на Android приложения, която позволява стартиране на тестове директно на JVM без емулатор или физическо устройство. Тя прихваща извикванията на Android SDK и предоставя shadow-обекти, емулиращи поведението на реални компоненти. Според Robolectric Documentation, 2025, shadow-обектите заместват около 15 хиляди класа на Android API, осигурявайки изолация на тестовете от платформата.

Основни точки

  • Robolectric — рамка за unit тестване на Android без емулатор, работеща на JVM
  • Shadow-обекти прихващат извиквания на Android SDK и емулират поведението на системата
  • Интеграция с JUnit 4 и 5 позволява използването на стандартни тестови runners
  • Тестове се изпълняват за секунди, а не минути, както в емулатора
  • Поддръжка на Jetpack Compose, фрагменти, intent-ове, ContentProvider и ресурси

Какво е Robolectric

Robolectric е рамка с отворен код, създадена през 2010 г. за ускоряване на тестването на Android приложения. Вместо да работи на емулатор или устройство, Robolectric предоставя shadow-имплементации на класове от Android SDK, които работят директно на Java Virtual Machine (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 компонент, но работи без native платформа.

Как работят shadow-овете

Shadow-обектите имплементират ключовите методи на оригиналните Android класове. Например ShadowTextView имитира методите getText(), setText(), getCurrentTextColor() и други. При извикване на textView.setText(„Hello“) 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“. Също така трябва да се посочи конфигурацията android:sdk във файла build.gradle и да се добави android:testInstrumentationRunner. За работа с Robolectric не е необходим плъгин android-test.

Основна 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 тестовете се пишат като обикновени unit тестове с @RunWith(RobolectricTestRunner.class) за JUnit 4 или чрез RobolectricExtension за JUnit 5. ActivityController управлява жизнения цикъл на Activity: create(), start(), resume(), pause(), stop(), destroy(). Това позволява детайлно тестване на всяко преминаване на състояние.

Тестване на Activity

За тестване на Activity се използва ActivityController, който последователно преминава през фазите на жизнения цикъл. Достъпът до Activity е чрез controller.get(). Всички компоненти на изгледа са достъпни чрез 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());
    }
}

Тестване на intent-ове и навигация

Robolectric прихваща извикванията на startActivity() и позволява проверка на изпратените intent-ове чрез 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 е идеален за бързи unit тестове, проверка на UI логика, бизнес компоненти и хранилища. Емулаторът е необходим за инструментационни тестове, проверка на интеграция с API, тестване на камера, сензори и производителност.

ХарактеристикаRobolectricЕмулатор
Скорост~5 сек на 100 теста~5 мин на 100 теста
СтартиранеБез изграждане на APKИзисква изграждане на APK
Реално APIShadow-емулацияNative Android SDK
Out-of-the-boxСамо JUnitВсякакви рамки

Тестване на ViewModel и Repository

Robolectric е отличен за тестване на ViewModel, Repository и UseCase — компоненти, които използват Android SDK, но не изискват реален UI. ViewModel се тества чрез обикновен JUnit тест с RobolectricExtension, като компонентите на жизнения цикъл (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. Персонализираните shadow-ове се регистрират чрез @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, биометрия, работа с реални файлове и native библиотеки. За тези сценарии са необходими инструментационни тестове на емулатора. 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 е unit рамка, работеща на 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.

Обобщение

  • Robolectric — рамка за бързо unit тестване на Android на JVM без емулатор
  • Shadow-обекти заместват над 200 класа на Android SDK, емулирайки тяхното поведение
  • Жизненият цикъл на Activity и Fragment се управлява чрез ActivityController с проверка на състояния
  • Тестване на intent чрез ShadowActivity позволява проверка на навигация и прехвърляне на данни
  • Интеграция с JUnit и Gradle не изисква допълнителни инструментационни runners
  • Анотация @Config задава версия на API, език, конфигурация на екрана и ресурси
  • Robolectric и Espresso се допълват: бързи unit тестове срещу инструментационни тестове

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също