Experience with Roboelectric Android unit tests?

In my work project, a bunch of android unit tests are run with the Roboelectric testrunner. To my understanding, it removes the need for an emulator by mocking away the Android SDK. It does this with native libraries.

When trying to run those tests, I get a bunch of errors along the lines of

/tmp/libconscrypt_openjdk_jni-linux-x86_6417242317095640000.so: /nix/store/whypqfa83z4bsn43n4byvmw80n4mg3r8-glibc-2.37-45/lib/libc.so.6: version `GLIBC_2.38' not found (required by /nix/store/jfilhsiqdgm4nks2z6labx3iq9qd077a-gcc-13.3.0-lib/lib/libstdc++.so.6)
java.lang.UnsatisfiedLinkError: /tmp/libconscrypt_openjdk_jni-linux-x86_6417242317095640000.so: /nix/store/whypqfa83z4bsn43n4byvmw80n4mg3r8-glibc-2.37-45/lib/libc.so.6: version `GLIBC_2.38' not found (required by /nix/store/jfilhsiqdgm4nks2z6labx3iq9qd077a-gcc-13.3.0-lib/lib/libstdc++.so.6)
	at java.base/java.lang.ClassLoader$NativeLibrary.load0(Native Method)
	at java.base/java.lang.ClassLoader$NativeLibrary.load(ClassLoader.java:2430)
	at java.base/java.lang.ClassLoader$NativeLibrary.loadLibrary(ClassLoader.java:2487)
	at java.base/java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2684)
	at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2617)
	at java.base/java.lang.Runtime.load0(Runtime.java:765)
	at java.base/java.lang.System.load(System.java:1835)
	at org.conscrypt.NativeLibraryUtil.loadLibrary(NativeLibraryUtil.java:52)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.conscrypt.NativeLibraryLoader$1.run(NativeLibraryLoader.java:297)
	at org.conscrypt.NativeLibraryLoader$1.run(NativeLibraryLoader.java:289)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at org.conscrypt.NativeLibraryLoader.loadLibraryFromHelperClassloader(NativeLibraryLoader.java:289)
	at org.conscrypt.NativeLibraryLoader.loadLibrary(NativeLibraryLoader.java:262)
	at org.conscrypt.NativeLibraryLoader.loadFromWorkdir(NativeLibraryLoader.java:201)
	at org.conscrypt.NativeLibraryLoader.load(NativeLibraryLoader.java:162)
	at org.conscrypt.NativeLibraryLoader.loadFirstAvailable(NativeLibraryLoader.java:106)
	at org.conscrypt.NativeCryptoJni.init(NativeCryptoJni.java:50)
	at org.conscrypt.NativeCrypto.<clinit>(NativeCrypto.java:64)
	at org.conscrypt.OpenSSLProvider.<init>(OpenSSLProvider.java:58)
	at org.conscrypt.OpenSSLProvider.<init>(OpenSSLProvider.java:51)
	at org.conscrypt.OpenSSLProvider.<init>(OpenSSLProvider.java:47)
	at org.robolectric.android.internal.AndroidTestEnvironment.setUpApplicationState(AndroidTestEnvironment.java:181)
	at org.robolectric.RobolectricTestRunner.beforeTest(RobolectricTestRunner.java:283)

Has anybody had any success of using this test runner under NixOS? Or understands the problem and has a fix?

Because I’m a bit confused: This thing uses artefacts from the nix store, but then it seems that these don’t find their GLIBC_2.38 dependency, which shouldn’t be possible under NixOS?! If something from outside the store couldn’t find dependencies I’d get it, but this…?!

Where did you get that roboelectric package? Can you share the source?

No, that’s the problem. It’s not packaged. The customers gradle downloads it automatically from somewhere. My solution is to run the stuff in a dev container. Which works pretty well, to be fair. Just a few hickups and gotchas

Ahuh. Perhaps nix-ld would help.

It does look interesting, thanks! I need to have closer look at it. From a first scan it seems to magically fix all of NixOS dynamic linker issues, but I expect there’s a catch somewhere…

Edit:
No catch, it’s just awesome, don’t know how I missed it so far. It should be featured much more prominently in a “make NixOS work with way less pain” section of the docs.

I’ve set it up in my config to be generally available on my system (not sure if that’s necessary), but set an empty list of packages, so it has no function (to avoid things just magically running in an irreproducible way without me noticing). Then I add packages in dev shells where I need them.