Unit testing Couchbase Lite on Android

I am trying to set up some unit tests that interact with CBL using Robolectric however I am stuck with the error java.lang.UnsatisfiedLinkError: no LiteCoreJNI in java.library.path which looks to be a limitation of Robolectric.

I haven’t been able to find much on unit test integration and almost nothing on later versions of 2.x…

Is there any doco I am missing?

Is there a way around the native library issue?

Failing that, is there a standard way of mocking CBL so I can do this as a standard unit test? We are currently using addChangeListener for many of our calls as a way of propagating updates via Rx so I really need to find a way to mock this mechanism…

@Ben_Neill,
Sorry, there is, as far as I can tell, no way to do this, at this time. I’ve found people that have managed to get a native library to work, under Robo, but I, at least, haven’t been able to get it to work, with ours.

… and no, no mocking layer. That is very much on my list of things to do. It’s a big job, though and I don’t have an ETA.

If you can say, specifically, what you are doing, I might be able to help. I haven’t actually done it but I should think that shimming a change listener into an Observable would be pretty straightforward…

-blake

Would you share any link of repo or something related to this? I want to explore couchbase-lite-C with Kotlin Native/Multiplatform.

So what I want to do is setup scenarios where I test that the query is correct within my repository. I can add an abstraction layer but it’ll be a lot of work and would be better served with an actual implementation, with results coming from a real database implementation like I had with SQLite…

If you can point me towards anyone that has got CBL running on Robo…

This is pretty old. I should think that the approach might still work, though: https://github.com/zhengxiaopeng/RobolectricSupportNativeLibs

So I looked into this, It looks like recompiling for mac shouldn’t be an issue, but I can’t see any way to prevent the loading of the native lib? That seems to be hardcoded into the CouchbaseLite.init() method…

Yes. Most of CBL is implemented in that library. It kind of wouldn’t make sense to try to run without it. There are hundreds of calls from the Java, to native methods in the library. I hope to make it possible to mock them, but it is a really big job and probably not something that is in scope for a client.

Have you considered re-examining what you are testing? E-E testing, of course. For most tests, though, there probably isn’t any reason for you to test Couchbase code. It’s not like we don’t make mistakes but, if we do, they are kind of out of your control. Maybe you could consider mocking at the CBL level?

The point of not loading it is so we can load our MacOS binary isn’t it?

I’m not attempting to test CB itself, more our implementation of it, the same as I did with Sqlite. Test our queries return what we expect, that streams fire off when expected, etc. This problem essentially makes most robolectric testing unviable.

At this point, mocking is one answer, however that’s pretty meh for integration tests and doesn’t looks like it’ll be trivial. We can run all these tests in an emulator, but that’s going to be pretty slow.

I’m not sure you understand, Ben. Couchbase Lite is primarily implemented in C++. The Java code is mostly a wrapper. Using Couchbase Lite without the native library is impossible.

I’m also confused about why the answer is not just “put the native library in a directory that is included in java.library.path”. It would have to be the Java variant, I’m guessing, but those are available from inside of the java desktop packages, or by compiling from source.

I understand that just fine Jens, the issue as I understand it is that the c++ library is not compiled for the arch that Robolectric requires. In order to recompile and serve up the native lib for MacOS, I need to be able to suppress the original lib being loaded… I don’t believe I can do that.

Will putting the native library in the path be enough? Looking at that approach they are selectively loading based off the Application class.

am I missing something?

The call in question is this right -> System.loadLibrary(LITECORE_JNI_LIBRARY); ?

What does RoboElectric have to say about this call? At a high level there are only two answers:

  1. Change the path to find the library you want
  2. Change the library to be in the path you want (extract JAR, swap out native lib, repackage JAR?)

Yep that’s the one.

Right, that makes sense. We should just have to do that whenever we upgrade CBL versions and supply the modified jar as a test dependency… I’ll give that a try.