New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Realm #1389

Open
kneth opened this Issue Nov 19, 2014 · 42 comments

Comments

Projects
None yet
@kneth

kneth commented Nov 19, 2014

A number of users of Realm (for Android) has asked if we support Roboelectric. Realm's development is very such driven by user feedback, and we would love to be able to let users do better testing using Roboelectric.

Realm relies on a core written in C++. We do have many JNI calls, and we need a .o file in order to get it to work. What does it require of Realm so Roboelectic can integrate support for it?

@erd erd added this to the 3.0 milestone Nov 19, 2014

@freezy

This comment has been minimized.

freezy commented Jan 19, 2015

If there are workarounds for testing an app with Robolectric that has Realm deeply wired into it, I'd like to hear about it. There was an approach once mocking the JNI calls but that only seems to work for Robolectric 1.x.

@kneth: How do you guys unit-test your apps?

@eygraber

This comment has been minimized.

eygraber commented Jan 20, 2015

This would be awesome.

@kneth

This comment has been minimized.

kneth commented Jan 20, 2015

@freezy Realm is a framework, and we run our unit tests on both emulators real devices to ensure that it will work for app developers.

Realm for Android builds on Realm core which is a C++ library. The code size is much larger and it is shared by OS X, iOS and Android bindings. We have a special test suite for that part.

The only apps we develop are small sample app. We monkey test them.

@freezy

This comment has been minimized.

freezy commented Jan 20, 2015

@kneth: I figured since you guys are earning your money by providing "enterprise services", you might be aware how people unit-test their apps with Realm.

@erd

This comment has been minimized.

Member

erd commented Jan 21, 2015

@kneth and I chatted about this and there are a few things that need to happen in order for Robolectric to support Realm: Realm needs to build a version of their native code that will run on a desktop machine. Once this is done, the Robolectric gradle plugin needs to be modified to set java.library.path to point to the extracted JNI. There may be other things that surface once we start testing, but those two items are needed for us to get started.

@freezy

This comment has been minimized.

freezy commented Jan 21, 2015

Great to see progress on this.

@kneth: Any estimation about how much work this involves would be very appreciated (and of course, if you're going to invest time into this).

@bmunkholm

This comment has been minimized.

bmunkholm commented Jan 21, 2015

Hi, Brian from Realm here.
We could very easily make a version for any one platform e.g. Mac, but then I assume people would start asking about Windows and various linux versions as well :-) So it quickly becomes somewhat hard to manage and distribute all those binaries. We are definitely going to do so at some point anyway. There are however a number of other feature request that currently are higher on the list, so giving a timeframe is really hard.
@erd Do you have any stats on the popularity of various platforms that robolectric is used on?

@hanibalsk

This comment has been minimized.

hanibalsk commented Jan 28, 2015

Roboelectric is quite popular on android devices and support or errors with realm is big problem for our app

@erd erd removed this from the 3.0 milestone Jan 28, 2015

@erd

This comment has been minimized.

Member

erd commented Jan 28, 2015

@bmunkholm - I don't have any data on actual usage, but anecdotally, I'm pretty sure that Mac and Linux would be the majority.

@vvictor10

This comment has been minimized.

vvictor10 commented Feb 19, 2015

@bmunkholm Any possibility of making this a priority? Roboelectric is the most popular way to unit test on the JVM and without support for Realm, it would be hard to make the jump. We are so close to making the decision to switch to Realm, but we definitely need the ability to test outside of a device or the emulator. Thanks.

@daterrell

This comment has been minimized.

daterrell commented Mar 5, 2015

I'd like to second this issue, but not with respect to Realm specifically.

My project has a few dependencies (in AAR) that we use to load native libraries. On-device testing/running using these libraries works, but Robolectric testing does not. I have built our native libraries for x86, and loaded them in the AARs, but the java.library.path is wrong. So I continue to get UnsatisfiedLinkError when attempting to load in a Robolectric test.

I can manually set the java.library.path in gradle:

tasks.withType(Test) {
systemProperty "java.library.path", '/some/path'
}

This helps in gradle runs, but not Android Studio, where the setting is in the unit test configuration. In either case, (gradle on command line or in Android Studio), and even with a hardcoded path to the libraries, Java fails to load them.

@erd erd changed the title from Supporting Realm to Support Realm Apr 24, 2015

@nilsi

This comment has been minimized.

nilsi commented Jun 5, 2015

Any progress on this?
Just to be clear, if I have an android app with one main activity that uses Realm. It's impossible for me to test the app with Robolectric right now? Or are there any hacks that I can use to mock Realm or ignore the exceptions or anything?
Thank you!

@erd

This comment has been minimized.

Member

erd commented Jun 5, 2015

When we have something to share, I'll be sure to update this issue.

The standard way of dealing with external dependencies like this would be to hide the Realm specific stuff behind an interface and use DI to inject a fake implementation in your unit tests.

@nilsi

This comment has been minimized.

nilsi commented Jun 5, 2015

Great! Do you know any examples where this is shown in practise? I'm having a hard time finding any. Anyway, will try and see if I can get it right.

@jongerrish

This comment has been minimized.

Contributor

jongerrish commented Jun 11, 2015

What kind of support are you expecting Robolectric to offer / fix?

I'm not familiar with Relm, but it seems to be implemented using native code, therefore, just like any other library that is implemented this way you will either need a version of that native code that runs on desktop computers (OSX/Windows/Linux) or you will need Relm to provide an alternative Java implementation.

Your other options are mocking out Relm, or building an in memory stub.

@gcmorrison

This comment has been minimized.

gcmorrison commented Jun 12, 2015

A good solution is to use dependency injection to use a test implementation
of your storage layer when running your tests. You can then use Mockito to
mock out your storage implementation and drive your test's behaviour
through that.

I admit it's a little bit inconvenient, but it works.

On Fri, Jun 12, 2015 at 10:20 AM, Virl notifications@github.com wrote:

I dont know. Just make it work!1

Sent from my iPhone

On 12 Jun 2015, at 01:37, Jonathan Gerrish notifications@github.com
wrote:

What kind of support are you expecting Robolectric to offer / fix?

I'm not familiar with Relm, but it seems to be implemented using native
code, therefore, just like any other library that is implemented this way
you will either need a version of that native code that runs on desktop
computers (OSX/Windows/Linux) or you will need Relm to provide an
alternative Java implementation.

Your other options are mocking out Relm, or building an in memory stub.


Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHub
#1389 (comment)
.

@y-yagi y-yagi referenced this issue Jul 20, 2015

Closed

Test #23

@ypresto

This comment has been minimized.

ypresto commented Jul 31, 2015

Realm already has x86 support. So we need just set java.library.path.

@ypresto

This comment has been minimized.

ypresto commented Jul 31, 2015

Android gradle plugin seems to be not extracting jni *.so files from jar (no lib*.so file found in build/ dir).

@ypresto

This comment has been minimized.

ypresto commented Jul 31, 2015

If someone trying to solve this, below extensions might be helpful for extracting so files in jar.

https://github.com/cjstehno/gradle-natives
https://github.com/nhachicha/android-native-dependencies

@ypresto

This comment has been minimized.

ypresto commented Aug 8, 2015

Related: #1171

@McPo

This comment has been minimized.

McPo commented Aug 12, 2015

To add to the above comments, I also doubt this can be done (Although there was talk that it previously supported it, Im not sure about that).

Ultimately to correct the no path found exception. On OSX you can copy it to usr/lib/java
And rename the file librealm-jni.so - > librealm-jni.jnilib

However it then issues the following similar error, showing the file is now read but not compatible.

java.lang.UnsatisfiedLinkError: /usr/lib/java/librealm-jni.jnilib: dlopen(/usr/lib/java/librealm-jni.jnilib, 1): no suitable image found.  Did find:
    /usr/lib/java/librealm-jni.jnilib: unknown file type, first eight bytes: 0x7F 0x45 0x4C 0x46 0x01 0x01 0x01 0x00
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)

This proves its not a simple solution as some imply. I may give it a go on a linux VM, might have better luck with that (I highly doubt it).

Also android-native-dependencies, appears to require the so files are available outside of the jar/aar. This isnt the case for realm and so shows a 404. The other library also doesn't appear to have any relevance to the actual problem.

Its also worth noting that Jake Wharton provided a clear response regarding this issue.
#782

@McPo

This comment has been minimized.

McPo commented Aug 12, 2015

Attempted the same only on Ubuntu, result is the same.

OpenJDK 64-Bit Server VM warning: You have loaded library /usr/lib/jni/librealm-jni.so which might have disabled stack guard. The VM will try to fix the stack guard now.
It's highly recommended that you fix the library with 'execstack -c <libfile>', or link it with '-z noexecstack'.

java.lang.UnsatisfiedLinkError: /usr/lib/jni/librealm-jni.so:
/usr/lib/jni/librealm-jni.so: wrong ELF class: ELFCLASS32 (Possible cause: architecture word width mismatch)
        at java.lang.ClassLoader$NativeLibrary.load(Native Method)
        at java.lang.ClassLoader.loadLibrary1(ClassLoader.java:1965)
        at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1890)
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1880)
        at java.lang.Runtime.loadLibrary0(Runtime.java:849)
        at java.lang.System.loadLibrary(System.java:1088)
        at io.realm.internal.RealmCore.loadLibrary(RealmCore.java:114)

Have also attempted using execstack, no difference. This was on a Trust 64 bit, will now attempt on 32 bit.

@McPo

This comment has been minimized.

McPo commented Aug 13, 2015

Made some progress on a 32 bit ubuntu installation

java.lang.UnsatisfiedLinkError: /usr/lib/jni/librealm-jni.so: liblog.so: cannot open shared object file: No such file or directory
        at java.lang.ClassLoader$NativeLibrary.load(Native Method)
        at java.lang.ClassLoader.loadLibrary1(ClassLoader.java:1965)
        at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1890)
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1880)
        at java.lang.Runtime.loadLibrary0(Runtime.java:849)
        at java.lang.System.loadLibrary(System.java:1088)
        at io.realm.internal.RealmCore.loadLibrary(RealmCore.java:114)
        at io.realm.internal.SharedGroup.<clinit>(SharedGroup.java:35)
        at io.realm.Realm.<init>(Realm.java:205)
        at io.realm.Realm.createAndValidate(Realm.java:594)
        at io.realm.Realm.create(Realm.java:564)
        at io.realm.Realm.getInstance(Realm.java:411)
        at io.realm.Realm.getInstance(Realm.java:368)
        at io.realm.Realm.getInstance(Realm.java:349)

I believe it is now complaining about liblog.so.
I grabbed liblog.so from https://github.com/sqlcipher/android-database-sqlcipher/blob/master/external/android-libs/x86/liblog.so
But no luck same error as above

Anyway more upto date information regarding this issue can be found on real-java repo.
realm/realm-java#904

@guillermomuntaner

This comment has been minimized.

guillermomuntaner commented Oct 21, 2015

Glad you are working on it. It would be very nice to be able to test Realm.

@jturolla

This comment has been minimized.

jturolla commented Nov 23, 2015

While this is not solved... I got the unity tests running with Robolectric and made a gist to make it easier for anyone trying to test realm:

https://gist.github.com/jturolla/25489e1b676957197201

I'm using Robolectric to test the entire app with Realm mocked. When I need to test some logic that involves the database I'm using the AndroidTestCase.

@niqdev

This comment has been minimized.

niqdev commented Dec 28, 2015

I hope this might help someone:
https://github.com/niqdev/dagger-realm-test

@khayamy001

This comment has been minimized.

khayamy001 commented Mar 18, 2016

The latest version of Realm (0.88.2) breaks the workaround mentioned by @jturolla since it now uses a gradle plugin. This means I cannot update my version of the library because none of my tests will work :(

@bachhuberdesign

This comment has been minimized.

bachhuberdesign commented Jun 4, 2016

Would love to see support for this as I have some apps that are heavily based around Realm.

@cgathergood

This comment has been minimized.

cgathergood commented Jun 10, 2016

Is there currently a way to ignore Realm to test other activities/fragments with Roboelectric?

I'm not trying to test anything Realm specific but receive a UnsatisfiedLinkError when building my activities with Roboelectric. Thanks

@ZakTaccardi

This comment has been minimized.

ZakTaccardi commented Jun 10, 2016

@cgathergood mock realm, inject a fake realm, etc. that's what dependency injection is for

@khayamy001

This comment has been minimized.

khayamy001 commented Jun 11, 2016

@cgathergood What I did was subclass my Application class and override the method where I initialize Realm. When testing i just don't load Realm at all and only test my interface layer that speaks to the Realm API's.

@mplacona

This comment has been minimized.

mplacona commented Jul 1, 2016

So as per @ZakTaccardi, I decided to take a similar approach to what @niqdev did here. Mocking all the things, but as it turns out, when you update Realm, that approach completely breaks.

The error is something like:

java.lang.UnsatisfiedLinkError: Can't load library: /var/folders/7f/xxctbvmx0ql52kx7rn55hm0mxvqnl9/T/android-tmp-robolectric5412460009663906587/app_lib/librealm-jni.dylib

And this

java.util.ServiceConfigurationError: org.robolectric.internal.ShadowProvider: Provider org.robolectric.shadows.support.v4.Shadows not a subtype

I've looked around, but really can't find anything that is helpful.

Has anyone been able to test Realm Realm 1.1.0? @kneth?

Any thoughts here appreciated

@cleemansen

This comment has been minimized.

cleemansen commented Jul 12, 2016

Any further progress here? I'm getting the mentioned java.lang.UnsatisfiedLinkError also during mocking all the things.

@mplacona

This comment has been minimized.

mplacona commented Jul 13, 2016

Hey @cleemansen have a look at how I solved in here.

@niqdev

This comment has been minimized.

niqdev commented Jul 19, 2016

Hi!
I've updated my project with Realm v1.x and my working solution for java.lang.UnsatisfiedLinkError was to use a different Application for testing

@Config(application = CustomApplicationTest.class)

The problem was that even if I mocked my DatabaseRealm wrapper class and all Realm methods, it was still injected and databaseRealm.setup() invoked in CustomApplication#onCreate.

@apacha

This comment has been minimized.

apacha commented Feb 24, 2017

Does anyone know, what's the current state of this? It would really be great, if this issue gets fixed soon.

@xian xian added this to the to prioritize milestone Mar 2, 2017

@juanmendez

This comment has been minimized.

juanmendez commented Mar 8, 2017

I decided to mock Realm with PowerMockito, and so far I've been doing several test for different features. There is more to come. https://github.com/juanmendez/Mocking-Realm. The great thing about Realm is it is very intuitive to mock.

@xian

This comment has been minimized.

Member

xian commented Mar 9, 2017

I've asked the Realm maintainers if we can do anything to help... realm/realm-java#904 (comment)

@juanmendez

This comment has been minimized.

juanmendez commented Mar 15, 2017

In the event Realm will be testable in the near future with Robolectric, I still want to make my project available for anyone who wants to test in simple unit mode as it's the case right now. Thereafter, I will be glad to help including more features upon request. https://github.com/juanmendez/Mocking-Realm/blob/master/demo/app/src/test/java/info/juanmendez/mockrealmdemo/QueryTests.java

@virl

This comment has been minimized.

virl commented Mar 17, 2017

Supporting Realm may require fixing Looper support in Robolectric, because, as I understand, Realm heavily relies on them for cross-thread object exchange: #2977, #1993

@kneth

This comment has been minimized.

kneth commented Mar 17, 2017

That's correct. Realm is using Loopers to implement the auto-update and change listener features.

@jesuscast

This comment has been minimized.

jesuscast commented Aug 24, 2017

I'm not familiar with this problem, but the JNI does not support loading of native libraries from more than one classloader. This has been very problematic with roboelectric testing for me.

Reference:
http://docs.oracle.com/javase/7/docs/technotes/guides/jni/jni-12.html#libmanage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment