- Погружение в Robolectric
- Зачем тестировать Android-специфичный код?
- Проблемы тестирования кода, использующего Android
- Пути решения
- Robolectric
- Используем android.util.Log
- Тестируем android.util.Log
- Внутреннее устройство
- Shadow классы
- Связь Shadow c Robolectric
- Переопределение методов
- Переопределение конструкторов
- Вызов настоящего объекта
- Собственный Shadow
- RobolectricTestRunner
- InstrumentingClassLoader
- Производительность
- Опыт использования
- Android Unit Testing Framework
- Related tags
- Robolectric cannot download artifacts — all tests fail
- Description
- Unable to resolve artifact: Missing:
- Steps to Reproduce
- Robolectric Version
- Redesign database related shadows
- Apple Silicon support
- Description
- Robolectric & Android Version
- Robolectric crashes with new VectorDrawableCompat
- OutOfMemoryError PermGen space and hanging builds
- Still get java.lang.RuntimeException: Stub! in Robolectric 2.2
- ViewPager IllegalStateException
- FileNotFoundException when opening AssetFileDescriptor
- Description
- Steps to Reproduce
- Robolectric & Android Version
- Link to a public git repo demonstrating the problem:
- meta-data tag not parsed correctly in AndroidManifest.xml
- Handler doesn’t execute Runnables when using Robolectric 3
- Legacy resource mode NPE w/ Robolectric 4.7.3
- Description
- Steps to Reproduce
- Robolectric & Android Version
- Link to a public git repo demonstrating the problem:
- Handle more values in ShadowSystemProperties.getBoolean
- AutoCompleteTextView and Robolectric Limitations
- Description
- Steps to Reproduce
- Robolectric & Android Version
- Link to a public git repo demonstrating the problem:
- NoSuchMethodException for SpannableStringBuilder when Jetpack Compose also available in app
- Description
- Steps to Reproduce
- Robolectric & Android Version
- Link to a public git repo demonstrating the problem:
- Invalid sqliteBlobTooBigException when using Sqlite Native mode with Robolectric 4.7
- Description
- Steps to Reproduce
- Robolectric & Android Version
- Link to a public git repo demonstrating the problem:
- Snapshots publish
- Add a task to fetch nativeruntime artifacts from a GitHub CI run
- Investigate supporting WithType for single input parameter of shadow method
- Description
- Steps to Reproduce
- Robolectric & Android Version
- Link to a public git repo demonstrating the problem:
- WindowManager.getCurrentWindowMetrics returns Rect(0,0,0,0)
- Description
- Steps to Reproduce
- Robolectric & Android Version
- Restructure integration_tests/androidx_test with sharedTest pattern
- Description
- Steps to Reproduce
- Robolectric & Android Version
- Link to a public git repo demonstrating the problem:
- robolectric-4.7.3(Dec 1, 2021)
- robolectric-4.7.2(Nov 20, 2021)
- robolectric-4.7.1(Nov 18, 2021)
- robolectric-4.7(Nov 12, 2021)
- What’s Changed
- New Contributors
- robolectric-4.7-alpha-2(Nov 8, 2021)
- robolectric-4.7-alpha-1(Nov 5, 2021)
- robolectric-4.6.1(Jul 4, 2021)
- robolectric-4.6(Jul 2, 2021)
- Robolectric 4.6
Погружение в Robolectric
В мире Android-разработки всё чаще используют unit-тестирование. Проверка корректности работы отдельных модулей приложения помогает выявить и устранить ошибки в коде уже на ранних этапах. Вкупе с автоматизацией сборки, компонентными и интеграционными тестами, unit-тесты позволяют делать качественный продукт, независимо от размера вашей команды разработчиков.
Под катом расскажу о внутреннем устройстве фреймворка для unit-тестирования Android-приложений — Robolectric.
Зачем тестировать Android-специфичный код?
Для начала постараемся ответить на вопрос — зачем тестировать код в местах интеграции с Android фреймворком?
Resources — стоит тестировать корректность использования определенных строковых или каких либо других ресурсов приложения, т.к. они являются неотъемлемой частью бизнес — требований.
Parcelable — независимо от того используете ли вы средства автоматической генерации Parcelable или пишете реализацию вручную, стоит тестировать корректность восстановления объектов из их сериализованного представления.
SQLite — тестирование миграции данных, изменения схем, добавление новых таблиц, корректность выполнения запросов.
Intent / Bundle — для некоторых сценариев важно проверять корректность заполнения Intent, флаги, с которыми будет запущена следующая Activity или Service.
Не UI компоненты системы, такие как Camera, MediaPlayer, MediaRecorder, различные менеджеры и т.д.
Это только часть сценариев, при которых тестирование кода в местах интеграции с Android становится актуальной задачей.
Проблемы тестирования кода, использующего Android
При попытках решить эту задачу в лоб можно столкнуться со следующими проблемами:
RuntimeException c причиной — method not mocked при попытке запустить тест кода вызывающего какой — либо метод фреймворка. А если использовать следующую опцию в Gradle —
то, RuntimeException брошен не будет. Такое поведение может приводить к тяжело детектируемым ошибкам в тестах.
Другой проблемой тестирования являются final классы и великое множество static методов фреймворка, что еще сильнее усложняет тестирование кода который его использует.
Пути решения
Для всех вышеперечисленных проблем существуют определенные решения:
Использовать примитивные тестируемые обертки над местами интеграции вашего кода с фреймворком. В ваших тестах вы мокаете обертку и тестируете ее взаимодействие с вашим кодом. Тестирование обертки в виду ее простой реализации опускаете. Хотя на самом деле эту обертку тестировать нужно, а оставаться примитивной она будет недолгое время. В конце концов, вам надоест дублировать реализацию фреймворка Android ради тестирования. Не стоит забывать и про рост количества методов в вашем APK, к которому приведет данный подход.
Instrumented unit tests — самый точный вариант тестирования. Тесты выполняются на реальном устройстве или эмуляторе в настоящем окружении. Но за это придется расплачиваться долгой компиляцией, упаковкой APK, и медленным выполнением тестов.
PowerMock + Mockito — PowerMock позволит вам мокать static методы и final классы. В этом случае вам придется частично повторить поведение некоторых классов Android, что может привести к распуханию кода ответственного за подготовку моков в ваших тестах и затруднит их поддержку в дальнейшем.
Robolectric
Существует еще одно решение проблемы Unit-тестирования Android приложений — Robolectriс. Robolectric — это фреймворк, разработанный компанией PivotalLabs в 2010 году. Он занимает промежуточное положение между “голыми” JUnit тестами и инструментированными тестами, запускаемыми на устройстве, симулируя реальное Android окружение. Фреймворк представляет собой скомпилированный android.jar с обвязкой из утилит для запуска тестов и упрощения тестирования. Он поддерживает загрузку ресурсов, примитивную реализацию выдувания View, предоставляет локальную SQLite (sqlite4java), легко кастомизируем и расширяем.
Используем android.util.Log
Предположим, что мы разрабатываем библиотеку для сторонних разработчиков и хотим убедиться, что наша библиотека печатает в Logcat некоторую важную информацию.
Реализуем следующий интерфейс — Logger , с одним методом для вывода сообщений уровня “Info”.
Напишем реализацию AndroidLogger — которая будет использовать android.util.Log .
Тестируем android.util.Log
Напишем тест на Junit с помощью Robolectric и убедимся, что метод info нашей реализации AndroidLogger на самом деле печатает сообщения в Logcat с уровнем info.
Аннотацией @RunWith мы указываем, что будем запускать тест с помощью RobolectricTestRunner . В параметрах к аннотации @Config мы передаем класс BuildConfig и указываем версию Android SDK которую будет симулировать Robolectric.
В тесте мы вызываем метод info у объекта AndroidLogger . С помощью класса ShadowLog достаем последнее сообщение записанное в лог и делаем assert по его содержимому.
Внутреннее устройство
Внутреннее устройство Robolectric можно условно разделить на 3 части: Shadow классы, RobolectricTestRunner и InstrumentingClassLoader .
Shadow классы
Создатели Robolectric вводят новый тип “тестовых двойников” (test double) — Shadow. Согласно официальному сайту, Shadows — “… not quite Proxies, not quite Fakes, not quite Mocks or Stubs”.
Shadow объект существует параллельно реальному объекту и может перехватывать вызовы методов и конструкторов, тем самым изменяя поведение настоящего объекта.
Связь Shadow c Robolectric
Аннотацией @Implements указывается класс для которого предназначен конкретный Shadow-класс.
В аннотации @Config теста можно указать Shadow-классы которые не входят в стандартную поставку Robolectric.
Переопределение методов
Переопределенный в Shadow-классе метод помечается аннотацией Implementation, важно сохранить сигнатуру оригинального метода.
При переопределении native метода кодовое слово native опускается.
Переопределение конструкторов
Для переопределения конструктора в Shadow-классе реализуется метод __constructor__ с теми же аргументами.
Вызов настоящего объекта
Для получения ссылки на реальный объект в Shadow-классе достаточно объявить поле с типом “оттеняемого” объекта помеченное аннотацией @RealObject :
Robolectric предоставляет возможность вызвать настоящую реализацию метода, минуя Shadow реализацию, с помощью Shadow.directlyOn .
Собственный Shadow
Написание собственного Shadow-класса не является большой проблемой, даже для сторонней библиотеки не входящий в стандартную поставку с Android.
Напишем класс, получающий токен пользователя с помощью GoogleAuthUtil .
Реализуем Shadow-класс для GoogleAuthUtil позволяющий переопределить token для определенного Account :
Напишем тест для GoogleAuthInteractor с помощью Robolectric. В конфигурации к тесту укажем, что хотим использовать ShadowGoogleAuthUtil и инструментировать классы из пакета com.google.android.gms.auth .
RobolectricTestRunner
От Shadow классов перейдем к RobolectricTestRunner — это первая часть Robolectric с которой связываются ваши тесты. Раннер отвечает за динамическую загрузку зависимостей (Shadow-классы и android.jar для указанной версии SDK) во время выполнения тестов.
Robolectric конфигурируется аннотацией @Config , c помощью которой можно изменять параметры симулируемого окружения для тестового класса и для каждого теста в отдельности. Конфигурация для запуска тестов будет собираться последовательно по всей иерархии тестового класса от родителя к наследнику и, наконец, к самому тестируемому методу. Конфигурация позволяет настроить:
- версию Android
- путь к манифесту и ресурсам
- список текущих квалификаторов
- сторонние Shadow
- дополнительные имена пакетов для инструментирования
InstrumentingClassLoader
Перед запуском тестов RobolectricTestRunner подменяет системный ClassLoader на InstrumentingClassLoader .
InstrumentingClassLoader обеспечивает связь реальных объектов с Shadow-классами, подмену некоторых классов на классы фейков и проксирование вызовов определенных методов в Shadow-классы напрямую.
Robolectric не инструментирует классы из пакета java.* , поэтому вызовы методов отсутствующие в обыкновенной JVM, но добавленные в Android SDK, проксируются напрямую в Shadow в месте вызова.
В фреймворке существуют два варианта инструментирования загружаемых классов. Оригинальная реализация генерирует байткод, использующий внутренний интерфейс ClassHandler и реализующий его класс ShadowWrangler , по сути оборачивающая каждый вызов метода через Shadow-класс в отдельный Runnable подобный объект и вызывает его. В апреле 2015 года в проект был добавлен второй вариант модификации байткода, использующий JVM инструкцию invokeDynamic .
Во время инструментирования Robolectric добавляет к каждому загружаемому классу интерфейс ShadowedObject с одним единственным методом — $$robo$getData() , в котором настоящий объект возвращает свой Shadow.
Для каждого конструктора InstrumentingClassLoader создает приватный метод $$robo$$__constructor__ с сохранением его сигнатуры и инструкций (кроме вызова super ).
В свою очередь тело оригинального конструктора будет состоять из:
- Вызова super (если класс является наследником)
- Вызова приватного метода $$robo$init , который инициализирует приватное поле __robo_data__ соответствующим Shadow объектом
- Вызова переопределенного конструктора ( __constructor__ ) на Shadow объекте, если Shadow объект существует и соответствующий конструктор переопределен, в противном случае будет вызвана настоящая реализация ( $$robo$$__constructor__ ).
Конструктор модифицированный с использованием инструкции invokeDynamic :
Конструктор модифицированный с использованием ClassHandler:
Для инструментирования методов Robolectric использует аналогичный механизм, настоящий код метода выделяется в приватный метод с приставкой $$robo$$ и вызов метода делегируется Shadow объекту.
Метод модифицированный с использованием инструкции invokeDynamic :
Для native методов Robolectric опускает соответствующий модификатор и возвращает значение по умолчанию если этот метод не переопределен в Shadow классе.
Производительность
Robolectric далеко не самый производительный фреймворк. Запуск пустого теста на RobolectricTestRunner занимает около 2х секунд. По сравнению с “чистыми” JUnit тестами 2 секунды это существенная задержка.
Профилирование выполнения тестов на Robolectric показывает, что большую часть времени фреймворк тратит на инструментирование загружаемых классов.
Ниже приведены результаты профилирования Robolectric и связки PowerMock + Mockito для теста android.util.Log описанного выше.
Метод | мс. |
---|---|
java.lang.ClassLoader.loadClass(String) | 913 |
org.robolectric.internal.bytecode.InstrumentingClassLoader. getInstrumentedBytes(ClassNode, boolean) | 767 |
org.objectweb.asm.tree.ClassNode.accept(ClassVisitor) | 407 |
org.objectweb.asm.tree.MethodNode.accept(ClassVisitor) | 367 |
org.robolectric.internal.bytecode.InstrumentingClassLoader $ClassInstrumentor.instrument() | 298 |
org.objectweb.asm.ClassReader.accept(ClassVisitor, Attribute[], int) | 277 |
org.robolectric.shadows.ShadowResources.getSystem() | 268 |
Метод | мс. |
---|---|
org.powermock.api.extension.proxyframework.ProxyFrameworkImpl.isProxy(Class) | 304 |
org.powermock.api.mockito.repackaged.cglib.core.KeyFactory$Generator .generateClass(ClassVisitor) | 131 |
sun.launcher.LauncherHelper.checkAndLoadMain(boolean, int, String) | 103 |
javassist.bytecode.MethodInfo.rebuildStackMap(ClassPool) | 85 |
java.lang.Class.getResource(String) | 84 |
org.mockito.internal.MockitoCore. () | 67 |
Опыт использования
В настоящий момент в нашем проекте более 3000 Unit тестов, примерно половина из них используют Robolectric.
Столкнувшись с проблемами производительности фреймворка было принято решение использовать Robolectric только для тестирования ограниченного набора случаев:
- Parcelable
- Форматирование строк в ресурсах
- Не UI компоненты (Camera)
Для всех остальных случаев мы оборачиваем зависимости Android в легко тестируемые обертки или используем unmock-plugin для Gradle.
Видео с моим докладом на эту же тему на конференции MBLTdev 16
Источник
Android Unit Testing Framework
Related tags
Overview
Robolectric is the industry-standard unit testing framework for Android. With Robolectric, your tests run in a simulated Android environment inside a JVM, without the overhead of an emulator.
Here’s an example of a simple test written using Robolectric:
For more information about how to install and use Robolectric on your project, extend its functionality, and join the community of contributors, please visit http://robolectric.org.
Starting a New Project
If you’d like to start a new project with Robolectric tests you can refer to deckard (for either maven or gradle) as a guide to setting up both Android and Robolectric on your machine.
Building And Contributing
Robolectric is built using Gradle. Both IntelliJ and Android Studio can import the top-level build.gradle file and will automatically generate their project files from it.
Robolectric supports running tests against multiple Android API levels. The work it must do to support each API level is slightly different, so its shadows are built separately for each. To build shadows for every API version, run:
If you would like to live on the bleeding edge, you can try running against a snapshot build. Keep in mind that snapshots represent the most recent changes on master and may contain bugs.
Issues
Robolectric cannot download artifacts — all tests fail
Description
[Robolectric] : sdk=28; resources=BINARY Downloading from maven Downloading: org/robolectric/android-all/10-robolectric-5803371/android-all-10-robolectric-5803371.pom from repository sonatype at https://oss.sonatype.org/content/groups/public/ Error transferring file: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext) [WARNING] Unable to get resource ‘org.robolectric:android-all:pom:10-robolectric-5803371’ from repository sonatype (https://oss.sonatype.org/content/groups/public/): Error transferring file: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext) Downloading: org/robolectric/android-all/10-robolectric-5803371/android-all-10-robolectric-5803371.pom from repository central at http://repo1.maven.org/maven2 Error transferring file: Server returned HTTP response code: 501 for URL: http://repo1.maven.org/maven2/org/robolectric/android-all/10-robolectric-5803371/android-all-10-robolectric-5803371.pom [WARNING] Unable to get resource ‘org.robolectric:android-all:pom:10-robolectric-5803371’ from repository central (http://repo1.maven.org/maven2): Error transferring file: Server returned HTTP response code: 501 for URL: http://repo1.maven.org/maven2/org/robolectric/android-all/10-robolectric-5803371/android-all-10-robolectric-5803371.pom Downloading: org/robolectric/android-all/10-robolectric-5803371/android-all-10-robolectric-5803371.jar from repository sonatype at https://oss.sonatype.org/content/groups/public/ Error transferring file: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext) [WARNING] Unable to get resource ‘org.robolectric:android-all:jar:10-robolectric-5803371’ from repository sonatype (https://oss.sonatype.org/content/groups/public/): Error transferring file: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext) Downloading: org/robolectric/android-all/10-robolectric-5803371/android-all-10-robolectric-5803371.jar from repository central at http://repo1.maven.org/maven2 Error transferring file: Server returned HTTP response code: 501 for URL: http://repo1.maven.org/maven2/org/robolectric/android-all/10-robolectric-5803371/android-all-10-robolectric-5803371.jar [WARNING] Unable to get resource ‘org.robolectric:android-all:jar:10-robolectric-5803371’ from repository central (http://repo1.maven.org/maven2): Error transferring file: Server returned HTTP response code: 501 for URL: http://repo1.maven.org/maven2/org/robolectric/android-all/10-robolectric-5803371/android-all-10-robolectric-5803371.jar
Unable to resolve artifact: Missing:
- org.robolectric:android-all:jar:10-robolectric-5803371
Steps to Reproduce
Create a unit test with RobolectricTestRunner
Robolectric Version
Redesign database related shadows
Removes a lot of shadows connected with SQLiteDatabase and Cursor , makes Robolectric behaviour much closer to how real Android behaves.
Instead of a bunch of removed shadows we introduce implementations of SQLiteConntection and CursorWindow based on sqlite4java. This approach let us drop a lot of shadowing code and use real Android classes. However both implemented classes belong to a hidden Android API, which means we should be careful when add some new Android API level to what is supported by Robolectric (especially adding 2.x APIs).
Worth to mention in release notes:
- SQLiteDatabase#openDatabase opens on-disk database until its path parameter is set with «:memory:» value;
- DatabaseConfig annotation is gone
- some methods from the shadowed db are gone:
- in SQLiteDatabase : setThrowOnInsert , hasOpenCursors , getQuerySql , getConnection
Some time ago I faced with some inconsistencies in shadows of cursors and started digging first removing shadow of matrix cursor and then. This request is not a merge candidate right now but rather a proposal.
I’m playing with removing cursor shadows completely and shadowing only SQLiteConnection and CursorWindow instead (ShadowSQLiteConnection, ShadowCursorWindow).
I’ve already made some progress in this direction and have some of database related tests passing. And now I’d like someone from the main team to take a look at the approach and start discussion. Perhaps it’s not the way worth to be implemented.
Currently I have 2 main points that do not allow me to sleep sweetly:
- SQLiteConnection belongs to hidden API, and I’m not pretty sure what to do with old Android versions.
- Current JDBC driver cannot always satisfy needs of Android internal calls like providing number of columns without making a real query or registering custom collators. So that to have everything implemented right we should switch to some Java wrapper for direct SQLite API.
So please take a look and tell what you think: should I go on or would I rather stop, delete this branch, and forget :).
Apple Silicon support
Description
When perform robolectric test on Apple silicon, following error is raised
Robolectric & Android Version
JVM : Jetbrains Runtime from Intellij IDEA 2020.3.2 ( OpenJDK 64-Bit Server VM JBR-11.0.9.1.11-1145.77-jcef (build 11.0.9.1+11-b1145.77, mixed mode) ) Robolectric : 4.5.1 Android Compile SDK : 30
Robolectric crashes with new VectorDrawableCompat
When AppCompat tries to create a drawable from a given vector, Robolectric tests fail with the following exception:
Happens regardless of whether or not support vectors are enabled as specified here: http://android-developers.blogspot.com/2016/02/android-support-library-232.html
Relevant exception higher up:
AppCompat does some working around for vector drawables via its ResourcesWrapper and ContextWrapper classes, I think the solution for this is that Robolectric needs to work with this. See the bottom of https://medium.com/@chrisbanes/appcompat-v23-2-age-of-the-vectors-91cbafa87c88#.hq4q2olt3
OutOfMemoryError PermGen space and hanging builds
I have a suite consisting of almost 2000 tests that work with Robolectric 2.4. I have started updating the suite to work with 3.0-rc2 but I can only run about
700 tests before they fail with an OutOfMemoryError or hang. It seems that once I reach a certain size, the tests will fail. For example I will run X tests successfully, then I will add a few more test classes and the suite will fail. If I leave the newly added classes and remove some of the classes known to be successful, I can get a successful build again.
The conversion for the majority of tests was just a matter of using the RobolectricGradleTestRunner, adding @Config line and fixing references to Robolectric classes that were moved. Continuing to use RobolectricTestRunner instead of RobolectricGradleTestRunner fails in similar ways.
The following jvmargs are set in the gradle.properties file. Increasing the memory options does not help: org.gradle.jvmargs=-Xmx1024m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
There are a few failure scenarios I have seen:
Test execution hang with no output
«OutOfMemoryError: PermGen space» error followed by gradle stacktrace
One of the above or just test failure followed by a different class loading error each time: [ERROR] couldn’t load roboguice.activity.RoboActivity in [email protected]336
[ERROR] couldn’t load android.content.Context in [email protected]f2e
[ERROR] couldn’t load org.bouncycastle.jce.provider.BouncyCastleProvider in [email protected]098
In all cases, just removing a few test classes will allow the tests to succeed.
Given I have a suite of testcases that work with 2.4 and work with 3.0-rc2 in batches of
700 tests, It seems to point to something in the 3.0 changes that are causing these OOM errors.
Still get java.lang.RuntimeException: Stub! in Robolectric 2.2
I have a fairly complicated app that I’m trying to use with Robolectric 2.2. I’ve added the robolectric jar to the top of my classpath in IntelliJ but I still get:
Caused by: java.lang.RuntimeException: Stub! at com.amazon.device.messaging.ADMMessageReceiver. (Unknown Source) at com.my.android.push.adm.ADMPushMessageReceiver. (ADMPushMessageReceiver.java:15) . 31 more
My classpath is: robolectric junit-4.10 app dependencies
I’ve also tried: junit-4.10 robolectric app dependencies
I use this ivv.xml to retreive my dependencies:
and that brings down all of these jars which I add to my class path:
I’m using Robolectric 2.2 with the latest EAP IntelliJ. I noted that IntelliJ EAP was using the project root as a default for the working dir and have fixed this to use the module dir. Prior to that I could run my test without getting this error but it was having trouble finding resources. Please help!
ViewPager IllegalStateException
I have a problem similar to https://github.com/robolectric/robolectric/issues/1326
The stacktrace is the same, but the code is not. In my case I start a Fragment using FragmentTestUtil . That Fragment calls ViewPager.setCurrentItem when it has been started, so I can’t use this fix (https://github.com/robolectric/robolectric/issues/1326#issuecomment-68306634).
FileNotFoundException when opening AssetFileDescriptor
Description
One of the functions in my unit tests wants to open an AssetFileDescriptor . I tried to use RuntimeEnvironment.systemContext and ApplicationProvider.getApplicationContext() interchangeably.
- Using RuntimeEnvironment.systemContext gives me
- Using ApplicationProvider.getApplicationContext() gives me
The latter error was more descriptive. Following the message from the stack-trace, I tried to disable the aapt resource compression for all resources using the following Gradle config but with no luck. Regardless of the compression settings, I am able to open an AssetInputStream to a resource with ApplicationProvider.getApplicationContext() context but unable to open a file descriptor to the same resource.
Steps to Reproduce
Robolectric & Android Version
- Android SDK 29
- Robolectric 4.3.1
- Tests are targeted for SDK 21 and 28
Link to a public git repo demonstrating the problem:
You can play around with this test. It highlights the problem. https://github.com/ashutoshgngwr/noice/blob/refactor/sound-manager/app/src/test/java/com/github/ashutoshgngwr/noice/sound/PlaybackTest.kt
Links to https://github.com/robolectric/robolectric/issues/4091
meta-data tag not parsed correctly in AndroidManifest.xml
There are several issues all pointing to the same underlying problem, so I’m going to consolidate them here. #1397, #1025, #1071.
Handler doesn’t execute Runnables when using Robolectric 3
Handler for custom background thread (with looper) doesn’t execute Runnables when used from inside test class. Looper created successfully for the thread.
In test class, I’m waiting for async result via CountDownLatch.
How can I fix that?
Legacy resource mode NPE w/ Robolectric 4.7.3
Description
We ran into this because we’re using the android-all jar and Robolectric tests in a JVM-only module (no Android stuff) so we can’t do «includeAndroidResources» to kick it into binary resources mode. Trying to do this causes no resources to be found: systemProperty(«robolectric.resourcesMode», «binary»)
Steps to Reproduce
Run test in repro project.
One of our folks worked around this by replacing uses of the resourceTable field with calls to the getResourceTable() method in the shadow asset manager class.
Robolectric & Android Version
Link to a public git repo demonstrating the problem:
Handle more values in ShadowSystemProperties.getBoolean
Handle more values in ShadowSystemProperties.getBoolean
This better matches the implementation/documentation of the method — this behavior should be consistent for all Android versions, at least as far Android 1.5.
See https://cs.android.com/android/platform/superproject/+/master:system/libbase/parsebool.cpp for the real native implementation.
AutoCompleteTextView and Robolectric Limitations
Description
Hi, this is more of a question as to what the systemic limitations of Robolectric are, rather than asking for a fix.
I am trying to test clicking on a drop down selection of an AutoCompleteTextView. I created a test in /androidTest and a near identical test under /test. FragmentScenario + Espresso is used to do the actual testing.
I notice that the existing test for AutoCompleteTextView in the Roblectric repository only tests the count of the adapter, not whether the drop-down is in view hierarchy.
Is Robolectric intended to work in this case? I would like to know if the «write-once, run-anywhere» idea is ever going to be viable.
Steps to Reproduce
- Type into an AutoCompleteTextView such that a popup should be displayed
- Try to click on the text view
- Can find and click on the auto-complete text view
- Drop down item cannot be found
Robolectric & Android Version
Robolectric 4.7.3, Android SDK 31
Link to a public git repo demonstrating the problem:
NoSuchMethodException for SpannableStringBuilder when Jetpack Compose also available in app
Description
Noticed that our robolectric test where the system under test used SpannableStringBuilder would fail when Jetpack Compose was also enabled and built. When Jetpack Compose was not enabled, the issue would disappear.
But if we add the following, the test would pass and the method is found and the test would pass.
The exact error was the following:
Not sure what is causing it to happen yet. This happens with
Steps to Reproduce
Robolectric & Android Version
Kotlin 1.5.31 Robolectric 4.7 Android Api level 31
Link to a public git repo demonstrating the problem:
Invalid sqliteBlobTooBigException when using Sqlite Native mode with Robolectric 4.7
Description
When enabling Native mode, Robolectric throws an incorrect BlobTooBigException. Disabling Native mode (comment out the annotation in the repro code below) lets the test pass. Default max cursor size for Sqlite should be 2GB. This retrieves data that is only 5000 bytes.
Steps to Reproduce
Run this code in a unit test with Robolectric 4.7.3:
Robolectric & Android Version
4.7.3 Android Studio Arctic Fox and Chipmunk
Link to a public git repo demonstrating the problem:
See short repro unit test above
Snapshots publish
Add a task to fetch nativeruntime artifacts from a GitHub CI run
This makes it easier and more automated to add the set of nativeruntime shared libraries to build an uber JAR.
Fetching artifacts using an API requires a GitHub username and account token. These can be specified from the command line using environment variables.
Long-term, this logic could be relocated to a GitHub workflow, if a workflow exists to perform releases.
Investigate supporting WithType for single input parameter of shadow method
Description
Robolectric maybe need to add new shadow method with class type as input parameter, added from latest SDK, for example https://github.com/robolectric/robolectric/issues/6883. Developers can run related tests correctly when compileSdk is latest SDK. But if they change it to a lower SDK, related tests may failed because of NoClassDefFound problem. As @hoisie pointed out at https://github.com/robolectric/robolectric/pull/6884#issuecomment-980483259, we can investigate whether we can support WithType for single input parameter of shadow method.
It’s better if we can expand this feature to support simulation for non-shadow method with new class type, such as https://github.com/robolectric/robolectric/issues/6589. Maybe we can add internal wrapper methods likes shadow method to wrapper those normal methods with WithType .
Steps to Reproduce
Robolectric & Android Version
Latest Robolectric before this issue closed/fixed.
Link to a public git repo demonstrating the problem:
WindowManager.getCurrentWindowMetrics returns Rect(0,0,0,0)
Description
WindowManager.getCurrentWindowMetrics().getBounds is the new way to obtain window size however in Robolectric it returns empty Rect
Steps to Reproduce
Robolectric & Android Version
Robolectric 4.7.2 targetSdk 31
Restructure integration_tests/androidx_test with sharedTest pattern
Description
Ideally, the tests under integration_tests/androidx_test can also run on real emulator. It’s better if we can restructure this test module with sharedTest pattern(http://robolectric.org/blog/2021/10/06/sharedTest/), the same as ctesque. We can start to work for it after https://github.com/robolectric/robolectric/pull/6745 merged to reduce conflict problem, because it adds tests under integration_tests/androidx_test. After restructuring, related tests will be tested on emulator too at CI jobs.
Steps to Reproduce
Robolectric & Android Version
Latest master branch.
Link to a public git repo demonstrating the problem:
Releases(robolectric-4.7.3)
robolectric-4.7.3(Dec 1, 2021)
This is a minor release that fixes #6883, a NoClassDefError that can occur if the compileSdk Source code(tar.gz)
Source code(zip)
robolectric-4.7.2(Nov 20, 2021)
This is a minor release that fixes a memory leak of Theme objects in binary resources for Android S (#6872). Thanks @calvarez-ov for the report and helping debug.
robolectric-4.7.1(Nov 18, 2021)
This is a minor release that fixes #6858. In that issue, certain Android classes could not be mocked by Mockito due to some changes to Robolectric instrumentation performed on interfaces.
robolectric-4.7(Nov 12, 2021)
Robolectric 4.7 adds support for Android S (API level 31).
Another big feature is support for Apple Silicon (Mac M1). Robolectric 4.7 now contains its own native implementation of the android.database.sqlite package. For Mac M1 machines, this SQLite mode is the default. For other OS’s and architecture, use @SQLiteMode(NATIVE) to enable it. This new mode is currently only available for Mac and Linux. Native SQLite should be significantly faster, around 50-90% faster for SQLite operations, than the LEGACY SQLite mode. There were also several other performance improvements made for SQLite operations — #6687, #6690, and #6711 (thanks @al-broco!).
The support v4 shadows are also deprecated at this release, and they will be removed at Robolectric 4.8.
Robolectric 4.7 also supports JDK 17.
What’s Changed
- Clear cookies after test finished for CookieManagerTest by @utzcoz in https://github.com/robolectric/robolectric/pull/6581
- Only using ApplicationExitInfo for compile sdk 30 and above by @utzcoz in https://github.com/robolectric/robolectric/pull/6590
- Rebase PR 4064 — Fix NPE during saving state of WebView by @utzcoz in https://github.com/robolectric/robolectric/pull/6597
- Converting the String version of directlyOn(. ) to @Direct with reflector(. ). by @hoisie in https://github.com/robolectric/robolectric/pull/6598
- Add ITelephonyRegistry to ShadowServiceManager https://github.com/robolectric/robolectric/pull/6605
- Implement new #startActivity methods for ShadowCrossProfileApps. https://github.com/robolectric/robolectric/pull/6601
- Add ShadowMediaExtractor. https://github.com/robolectric/robolectric/pull/6592
- Converting onVsync calls from ReflectionHelpers to use @Direct with reflector(. ) instead. https://github.com/robolectric/robolectric/pull/6602
- Update ShadowDisplayEventReceiver to support S https://github.com/robolectric/robolectric/pull/6609
- Converting the proxy version of directlyOn(. ) to @Direct with reflector(. ). by @hoisie in https://github.com/robolectric/robolectric/pull/6610
- Fix Robolectric camera shadows to work with newer SDK versions. https://github.com/robolectric/robolectric/pull/6611
- Converting recycleUnchecked calls to use @Direct with reflector(. ) in place of ReflectionHelpers. https://github.com/robolectric/robolectric/pull/6603
- Cleaning up unnecessary @Direct annotations in DirectActivityReflector. https://github.com/robolectric/robolectric/pull/6616
- Fixing the incorrect method signature in AssetManagerReflector that breaks GitHub CI. https://github.com/robolectric/robolectric/pull/6612
- No longer automatically log everything in ShadowLog if stream is specified https://github.com/robolectric/robolectric/pull/6617
- Support IntBuffer with copyPixelsFromBuffer https://github.com/robolectric/robolectric/pull/6613
- Suppress missing /system/etc/fonts.xml log noise for SDK 27 https://github.com/robolectric/robolectric/pull/6618
- Add perf stats for reflector class definition https://github.com/robolectric/robolectric/pull/6624
- Use Object to replace GnssAntennaInfo.Listener at ShadowLocationManager by @utzcoz in https://github.com/robolectric/robolectric/pull/6623
- Trimming the localrepository string. by @Squadella in https://github.com/robolectric/robolectric/pull/6653
- Merging the the separate Reflector interfaces for Message into one main interface. https://github.com/robolectric/robolectric/pull/6619
- Remove OldClassInstrumentor https://github.com/robolectric/robolectric/pull/6621
- Remove unnecessary ShadowLegacyMessage.isInUse https://github.com/robolectric/robolectric/pull/6626
- Converting directlyOn(. ) to @Direct with reflector(. ) in ShadowWindow and ShadowPhoneWindow. https://github.com/robolectric/robolectric/pull/6625
- Intercept calls to methods in <@link Socket>not present in the OpenJDK. https://github.com/robolectric/robolectric/pull/6622
- Use bulk operations in copyPixels
Buffer https://github.com/robolectric/robolectric/pull/6628 - Improve reflector caching using a regular HashMap https://github.com/robolectric/robolectric/pull/6629
- Add shadow method ShadowLauncherApps#getShortcutConfigActivityList. https://github.com/robolectric/robolectric/pull/6631
- Add OnPermissionChangedListener implementation to ShadowPackageManager. https://github.com/robolectric/robolectric/pull/6627
- Update minSdkVersion to 14 in some integration_test manifests https://github.com/robolectric/robolectric/pull/6630
- Merge InvokeDynamicClassInstrumentor into ClassInstrumentor https://github.com/robolectric/robolectric/pull/6632
- Add a shadow method for PackageManager#getText which gets a String associated with package name and resource id. https://github.com/robolectric/robolectric/pull/6634
- Pass through openInputStream calls for SCHEME_ANDROID_RESOURCE https://github.com/robolectric/robolectric/pull/6636
- Names thread used by ShadowFileObserver to match behavior of FileObserver. https://github.com/robolectric/robolectric/pull/6640
- Migrate from AnnotationValue#toString to auto-common ‘s AnnotationValues.toString . https://github.com/robolectric/robolectric/pull/6638
- Fix fidelity issue with Cursor.getBlob on a String column https://github.com/robolectric/robolectric/pull/6641
- Remove InvokeDynamic perf stats https://github.com/robolectric/robolectric/pull/6644
- Fix SQLiteDatabaseTest foreign key test to match Android behavior https://github.com/robolectric/robolectric/pull/6643
- Add cardId support for ShadowEuiccManager. https://github.com/robolectric/robolectric/pull/6642
- Add OnUidImportanceListener implementation to ShadowActivityManager and SCREEN_ON/SCREEN_OFF broadcasts to ShadowPowerManager. https://github.com/robolectric/robolectric/pull/6639
- Instrument default interface methods https://github.com/robolectric/robolectric/pull/6645
- Support Object array and Iterable as return type for single parameter by @utzcoz in https://github.com/robolectric/robolectric/pull/6696
- Rebase PR 6265: Bounds check the correct variable. by @utzcoz in https://github.com/robolectric/robolectric/pull/6706
- Remove allocation in ShadowCursorWindow.Data init by @al-broco in https://github.com/robolectric/robolectric/pull/6711
- internal https://github.com/robolectric/robolectric/pull/6654
- Add perfstats for ShadowSQLiteConnection https://github.com/robolectric/robolectric/pull/6659
- Add support for startWatchingMode() with flags. https://github.com/robolectric/robolectric/pull/6661
- Make isOpActive() public, so it can be used in tests below Android R. https://github.com/robolectric/robolectric/pull/6662
- Add a sqlite test using LIKE ? ESCAPE ? https://github.com/robolectric/robolectric/pull/6666
- Throw an exception if a query is performed using SQLiteDatabase.execSQL https://github.com/robolectric/robolectric/pull/6672
- Add isAutoRevokeWhitelisted implementation to ShadowPackageManager. https://github.com/robolectric/robolectric/pull/6673
- Add support for setting smart replies on ShadowRanking object, so getSmartRanking method can be used in tests. https://github.com/robolectric/robolectric/pull/6667
- Use full class name in the SQLiteConnection shadow https://github.com/robolectric/robolectric/pull/6679
- Improve NFC testability: https://github.com/robolectric/robolectric/pull/6587
- Add experimental sqlite shadows derived from AOSP SQLite https://github.com/robolectric/robolectric/pull/6670
- Exclude built-in config from being reloaded in Configuration registry https://github.com/robolectric/robolectric/pull/6680
- Make legacy ShadowSQLiteConnection implementation methods protected https://github.com/robolectric/robolectric/pull/6681
- Newly added shadow class for MediaStore is exposed to open source rebolectric library https://github.com/robolectric/robolectric/pull/6665
- Update ShadowAppWidgetManager to better handle RemoteViews with multiple layouts https://github.com/robolectric/robolectric/pull/6677
- Add shadow functionality for removing bonds(systemAPi) https://github.com/robolectric/robolectric/pull/6682
- Add support for NetworkInfo.extraInfo to ShadowNetworkInfo https://github.com/robolectric/robolectric/pull/6683
- Update default SQLite synchronous and journal modes https://github.com/robolectric/robolectric/pull/6687
- Add a null check to ShadowCursorWindow.put
https://github.com/robolectric/robolectric/pull/6675 - Add parameterized test name method to the test runner https://github.com/robolectric/robolectric/pull/6686
- Add ability to uninstall app widgets to ShadowAppWidgetManager.java https://github.com/robolectric/robolectric/pull/6693
- Add ShadowInetAddressUtil class https://github.com/robolectric/robolectric/pull/6694
- Add @InlineMe to deprecated ShadowLooper APIs. https://github.com/robolectric/robolectric/pull/6689
- Add @InlineMe to deprecated, inlineable APIs. https://github.com/robolectric/robolectric/pull/6455
- Add setAnchor to ShadowAccessibilityWindowInfo https://github.com/robolectric/robolectric/pull/6699
- Fix an ArrayIndexOutOfBoundsException in ByteBucketArray https://github.com/robolectric/robolectric/pull/6700
- Add missing implementation for __android_log_assert https://github.com/robolectric/robolectric/pull/6701
- Remove mocking from FragmentControllerTest https://github.com/robolectric/robolectric/pull/6703
- Add API to retrieve Intent used to start SpeechRecognizer https://github.com/robolectric/robolectric/pull/6692
- Update default SQLite synchronous mode when WAL is enabled https://github.com/robolectric/robolectric/pull/6690
- Fix formatting in ShadowSQLiteConnectionsTest https://github.com/robolectric/robolectric/pull/6712
- Add a SQLite mode that enables the new native Android SQLite shadows https://github.com/robolectric/robolectric/pull/6709
- Use offset from BufferInfo instead of ByteBuffer for ShadowMediaMuxer#writeSampleData by @utzcoz in https://github.com/robolectric/robolectric/pull/6695
- Support to open fd for uncompressed file in asset by @utzcoz in https://github.com/robolectric/robolectric/pull/6649
- Update gradle wrapper to 7.2 by @utzcoz in https://github.com/robolectric/robolectric/pull/6738
- Improve resetter for NfcAdapter and CardEmulation by @utzcoz in https://github.com/robolectric/robolectric/pull/6749
- Remove debug print statement https://github.com/robolectric/robolectric/pull/6714
- Fixes WindowInfo children not cloned in ShadowAccessibilityWindowInfo https://github.com/robolectric/robolectric/pull/6718
- Clarify ShadowLooper.idle message when test fails. https://github.com/robolectric/robolectric/pull/6719
- Skip ErrorProne on GitHub CI runs https://github.com/robolectric/robolectric/pull/6728
- Migrate off deprecated mockito APIs https://github.com/robolectric/robolectric/pull/6729
- Remove CircleCI metadata https://github.com/robolectric/robolectric/pull/6730
- Fix ShadowMediaPlayer#prepare() to invoke prepared listener on handler instead of executing directly on calling thread. https://github.com/robolectric/robolectric/pull/6731
- Delete ShadowBaseLooper https://github.com/robolectric/robolectric/pull/6733
- Include stack trace in System.log[WE] calls. https://github.com/robolectric/robolectric/pull/6735
- Implemented startForeground(int, Notification, int). https://github.com/robolectric/robolectric/pull/6717
- Fix spurious CloseGuard errors in Surface and SurfaceControl https://github.com/robolectric/robolectric/pull/6739
- Specify LEGACY SQLite mode for ShadowSQLiteConnectionTest https://github.com/robolectric/robolectric/pull/6746
- Add CMake build for SQLite native artifacts by @hoisie in https://github.com/robolectric/robolectric/pull/6720
- Deprecate ShadowSwipeRefreshLayout. by @utzcoz in https://github.com/robolectric/robolectric/pull/6710
- Add CI job to check aggregateDocs by @utzcoz in https://github.com/robolectric/robolectric/pull/6748
- Deprecate the supportv4 shadows as mentioned in #6185 by @alsutton in https://github.com/robolectric/robolectric/pull/6194
- Rework api classification and enforcement. https://github.com/robolectric/robolectric/pull/6755
- Add toString to ShadowApplication.Wrapper https://github.com/robolectric/robolectric/pull/6736
- Use more conventional name for the native runtime library https://github.com/robolectric/robolectric/pull/6764
- Add setWifiApConfiguration & getWifiApConfiguration to ShadowWifiManager https://github.com/robolectric/robolectric/pull/6763
- Make IntentsTest work on device without browser. https://github.com/robolectric/robolectric/pull/6765
- Merging HardwareRendererCompat fixes into one branch by @dmeng in https://github.com/robolectric/robolectric/pull/6773
- Don’t use HARDWARE bitmaps in Bitmap#createBitmap. https://github.com/robolectric/robolectric/pull/6766
- Fix missing imports when building on Mac OSX. https://github.com/robolectric/robolectric/pull/6771
- Update ShadowInCallService so that onCallAudioStateChanged callback is invoked when the audio route is changed. https://github.com/robolectric/robolectric/pull/6758
- Reduce usage for this$0 by @utzcoz in https://github.com/robolectric/robolectric/pull/6760
- Update nativeruntime CMake build to support Mac M1 by @hoisie in https://github.com/robolectric/robolectric/pull/6774
- Use the display ID in the provided ActivityOptions when launching activities, instead of always using the default display. https://github.com/robolectric/robolectric/pull/6697
- Add ctesque common tests to androidTest by @utzcoz in https://github.com/robolectric/robolectric/pull/6570
- Create a separate task to prefetch non-instrumented SDKs by @hoisie in https://github.com/robolectric/robolectric/pull/6778
- Clarify error message if the SQLite submodule is missing by @hoisie in https://github.com/robolectric/robolectric/pull/6786
- Make implementation classes protected on ShadowRenderNode by @hoisie in https://github.com/robolectric/robolectric/pull/6818
- Support self notification callbacks for AppOpsManager https://github.com/robolectric/robolectric/pull/6788
- Add a ShadowPackageBackwardCompatibility class to handle when multiple APIs are on the classpath https://github.com/robolectric/robolectric/pull/6790
- Always look for tzdata in the corresponding android-all jar instead of the classpath https://github.com/robolectric/robolectric/pull/6789
- Fix NPE when calling Path.arcTo with an invalid arc https://github.com/robolectric/robolectric/pull/6797
- Add support to system flags on ShadowWindow https://github.com/robolectric/robolectric/pull/6792
- Synchronize BinderService.getBinder https://github.com/robolectric/robolectric/pull/6807
- Add a binder service for TELEPHONY_SERVICE in ShadowServiceManager. https://github.com/robolectric/robolectric/pull/6808
- Add support for Android S https://github.com/robolectric/robolectric/pull/6776
- Add a test for getting and setting the global animation duration https://github.com/robolectric/robolectric/pull/6809
- Add supports of addOnActiveSessionsChangedListener with 3-arguments for ShadowMediaSessionManager. https://github.com/robolectric/robolectric/pull/6813
- Bump AGP to 7.1.0-beta02 by @utzcoz in https://github.com/robolectric/robolectric/pull/6815
- Default to native Android SQLite on the Mac M1 https://github.com/robolectric/robolectric/pull/6819
- Update ShadowRenderNodeAnimator to direct reflector https://github.com/robolectric/robolectric/pull/6821
- Turn off shadowOf generation for RoleControllerManager https://github.com/robolectric/robolectric/pull/6822
- Deprecate the proxy version of directlyOn https://github.com/robolectric/robolectric/pull/6823
- Update ShadowApplicationPackageManager.getPackageArchiveInfo to use reflector https://github.com/robolectric/robolectric/pull/6825
- Migrate supportv4 shadows from directlyOn proxy to reflector https://github.com/robolectric/robolectric/pull/6826
- Ensure that ShadowAccessibilityRecord fields are preserved during AccessibilityEvent copy. https://github.com/robolectric/robolectric/pull/6820
- Migrate to use platform InstrumentationRegistry for LocalActivityInvoker by @utzcoz in https://github.com/robolectric/robolectric/pull/6787
- Use direct reflector for AcccessibiltyRecord.init in https://github.com/robolectric/robolectric/pull/6831
- Add ShadowTimePickerDialog.getIs24HourView in https://github.com/robolectric/robolectric/pull/6805
- Add libicu as a git submodule by @hoisie in https://github.com/robolectric/robolectric/pull/6833
- Disable the universal library for Mac OS by @hoisie in https://github.com/robolectric/robolectric/pull/6845
- Bump asm to 9.2 by @utzcoz in https://github.com/robolectric/robolectric/pull/6844
- Add workflow that builds native runtime and uploads artifacts by @hoisie in https://github.com/robolectric/robolectric/pull/6827
New Contributors
- @Squadella made their first contribution in https://github.com/robolectric/robolectric/pull/6653
- @al-broco made their first contribution in https://github.com/robolectric/robolectric/pull/6711
- @dmeng made their first contribution in https://github.com/robolectric/robolectric/pull/6773
Full Changelog: https://github.com/robolectric/robolectric/compare/robolectric-4.6.1. robolectric-4.7
robolectric-4.7-alpha-2(Nov 8, 2021)
*NOTE: Robolectric 4.7-alpha-2 is a outdated preview release; please use 4.7 or later instead.
robolectric-4.7-alpha-1(Nov 5, 2021)
NOTE: Robolectric 4.7-alpha-1 is a outdated preview release; please use 4.7 or later instead.
robolectric-4.6.1(Jul 4, 2021)
This is a minor release that fixes #6589, in which ShadowActivityManager contained a reference to android.app.ApplicationExitInfo, introduced in SDK 30, in public method. This caused shadowOf to fail if the target SDK was Source code(tar.gz)
Source code(zip)
robolectric-4.6(Jul 2, 2021)
Robolectric 4.6
The highlights of this release are:
- Uses preinstrumented jars by default, significantly decreasing startup time.
- Massive fidelity improvements for Bitmap and BitmapFactory.
- Tons of bug fixes and fidelity improvements.
Источник