FVod FVod - 1 month ago 27
Android Question

Instrumented test with Realm failing

I'm implementing an instrumented test to test a Database Data Source class that is using Realm. So now I'm facing some problems about how to use fixtures and how to mock Realm.
My database data source looks like:

public class DatabaseDataSource {
private Realm realm;

public DatabaseDataSource(Realm realm) {
this.realm = realm;
}


public Observable<RealmResults> getContacts(String firstName, String lastName, String city, String zipCode) {

final RealmQuery realmQuery = realm.where(Contact.class);
if(!TextUtils.isEmpty(firstName)) {
realmQuery.contains("firstName", firstName);
}
if(!TextUtils.isEmpty(lastName)) {
realmQuery.contains("lastName", lastName));
}
if(!TextUtils.isEmpty(city)) {
realmQuery.contains("city", city);
}
if(!TextUtils.isEmpty(zipCode)) {
realmQuery.contains("zipCode", zipCode);
}

return realmQuery.findAll()
.asObservable();
}
}


I want to have a list of contacts in my mocked realm so I can check that filtering is working fine. How can I do that?
I've tried doing:

@RunWith(AndroidJUnit4.class)
public class DatabaseDataSourceTest extends BaseInstrumentedTest{

private DatabaseDataSource databaseDataSource;

private List<Contact> contacts;

@Before
public void setup() {
Realm.init(InstrumentationRegistry.getTargetContext());
Realm.setDefaultConfiguration(new RealmConfiguration.Builder().build());

databaseDataSource = new DatabaseDataSource(new DatabaseClient());
}

@Test
public void trial() throws Exception {
subscribeContactsListObservable(databaseDataSource.getContacts("firstName", null, null, null));

assertEquals(2, contacts.size());

}

private void subscribeContactsListObservable(final Observable<RealmResults> observable) {
notaries = null;
observable.map(new Func1<RealmResults, List<Contact>>() {
@Override
public List<Notary> call(RealmResults realmResults) {
return realmResults != null? new ArrayList<>(realmResults) : null;
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<Contact>>() {
@Override
public void onCompleted() {
contacts = null;
}

@Override
public void onError(Throwable e) {
contacts = null;
}

@Override
public void onNext(List<Contact> contactsList) {
contacts = contactsList;
}
});
}


}

But the test is failing when doing the Observable.subscribe with the following exception:

You can't register a listener from a non-Looper thread or IntentService thread.


What may I do?

Thanks in advance

Answer

Well it specifically tells you the solution to your problem in that error message:

You can't register a listener from **a non-Looper thread** or IntentService thread. 

This is because asObservable() needs to register a RealmChangeListener in order to listen to changes in the Realm.

The instrumentation thread is a non-looper thread, so that means you can't listen to changes in it.

Solution, you need to either use a Looper thread (like the main thread), or create a Looper thread, and create the Realm instance in that looper thread. Conveniently, RxAndroid features a so-called LooperScheduler which you can create using AndroidSchedulers.from(Looper), which allows you to execute logic on an arbitrary looper thread.

A possibility is looking into how Realm already tests their looper-related stuff with this RunInLooperThread test rule.