How to use the inMemory() setting?

When I try to use the inMemory() setting, I run into various problems.

Roughly it looks like this:

schema = setOf(
…RealmObject declarations

In Unit tests it causes an ExceptionInInitializerError with NullPointerException.
In Robolectric or Instrumentation tests it causes the following:
kotlin.UninitializedPropertyAccessException: lateinit property filesDir has not been initialized.

What am I doing wrong?

The issue is that Android unittests are running in a non-Android JVM environment, but the infrastructure in AGP is pulling in Android dependencies for the test. The dependencies are not properly initialized when not running on an device/emulator.

We are in the process of migrating to the new Android source set layout from Kotlin 1.8 and you can track the progress in Migrate to new Android source sets for tests introduced in Kotlin 1.8 by cmelchior · Pull Request #1399 · realm/realm-kotlin · GitHub.

Until that you will have to run Android tests (both unit tests and device test) on a device/emulator.

That’s what I’m trying to do. That’s where I got the second exception.

I’m working on an Android only project, so the ticket is not relevant to me, I think.

Hmm, okay. Then it might be that our initializer, that picks up the context, just isn’t triggered correctly. We use the App Startup infrastruture as described in App Startup  |  Android Developers for that. Might be that Robolectric has an initializer that is running before ours. Would you be able to inspect the app manifest to see if Robolectric involves any initializers (App Startup  |  Android Developers). If so then we might be able to control the ordering of them by providing a custom initializer that depends on both.

That makes sense now, because we use Initializers, and when I set up the project, I had to add RealmInitializer as a dependency for a few Initializers to make it work and remove the very same error message with the filesDir.
However, now I run into this in normal Ui tests as well, even when I turn HiltAndroidRule off. Do I need to pass context somehow in tests?

I think I solved it. We still used (even with Hilt off) a custom AndroidJUnitRunner with a custom Application. I added RealmInitializer to this like this:

        val appInitializer = AppInitializer.getInstance(this)

And it works! Thanks.

Great to hear.

… Claus

My last comment above solved the problems with Instrumentation tests. Now as the last part of our migration, I delete SQLite DataSources and convert their Robolectric integration Unit tests to target the Realm DataSources.
However, I run into a similar problem as before. Here is the stack trace:

com.getkeepsafe.relinker.MissingLibraryException: Could not find 'librealmc.dylib'. Looked for: [armeabi-v7a], but only found: [].
androidx.startup.StartupException: com.getkeepsafe.relinker.MissingLibraryException: Could not find 'librealmc.dylib'. Looked for: [armeabi-v7a], but only found: [].
	at androidx.startup.AppInitializer.doInitialize(
	at androidx.startup.AppInitializer.doInitialize(
	at androidx.startup.AppInitializer.initializeComponent(
	at app//org.robolectric.util.PerfStatsCollector.measure(
	at app//org.robolectric.util.PerfStatsCollector.measure(
	at org.robolectric.RuntimeEnvironment.getApplication(
	at app//org.robolectric.RobolectricTestRunner.beforeTest(
	at app//org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$2(
	at app//org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(
	at java.base@17.0.5/
	at java.base@17.0.5/java.util.concurrent.ThreadPoolExecutor.runWorker(
	at java.base@17.0.5/java.util.concurrent.ThreadPoolExecutor$
	at java.base@17.0.5/
Caused by: com.getkeepsafe.relinker.MissingLibraryException: Could not find 'librealmc.dylib'. Looked for: [armeabi-v7a], but only found: [].
	at com.getkeepsafe.relinker.ApkLibraryInstaller.installLibrary(
	at com.getkeepsafe.relinker.ReLinkerInstance.loadLibraryInternal(
	at com.getkeepsafe.relinker.ReLinkerInstance.loadLibrary(
	at com.getkeepsafe.relinker.ReLinker.loadLibrary(
	at com.getkeepsafe.relinker.ReLinker.loadLibrary(
	at io.realm.kotlin.internal.AndroidUtilsKt.loadAndroidNativeLibs(AndroidUtils.kt:14)
	at io.realm.kotlin.internal.RealmInitializer.create(RealmInitializer.kt:42)
	at io.realm.kotlin.internal.RealmInitializer.create(RealmInitializer.kt:30)
	at androidx.startup.AppInitializer.doInitialize(
	at androidx.startup.AppInitializer.doInitialize(
	at androidx.startup.AppInitializer.initializeComponent(
	... 17 more

Important to note, that we have normal Unit tests with mocked Realm, but these are integration tests with in-memory Realm.
I found some related questions on the internet, but they are mostly old and probably outdated. I found this ticket too, which is outstanding, but this is for realm-java, and it seems there is no more blockers to add Robolectric support:

So ultimately the question is: is Robolectric supported for in-memory Realm for realm-kotlin?