question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Testing findAllAsync asChangesetObservable queries with RunTestInLooperThread

See original GitHub issue

Hi, guys! Thank you for your product. I am trying to write unit-tests for my DAO classes, that uses Realm. I use RunInLooperThread rule like in your RealmAsyncQueryTests class to test methods with findAllAsync calls. And i got the problem with RealmResults returned during the test.

Goal

I would like to get loaded RealmResults after results.addChangeListener(listener); is called under the hood of asChangesetObservable.

Expected Results

First emit contains not loaded RealmResults, according to emitter.onNext(new CollectionChange<>(results, null)); in changesetsFrom implementation. But second emit should contain loaded RealmResults according to documentation

Actual Results

I got RealmResults with isLoaded = false and it contains my data. RealmResults with isLoaded = true will never be returned from Observable.

E.g. full stack trace with exception java.lang.AssertionError: Expected: [com.wayray.element.core.data.CarData@0] (class: SingletonList), Actual: [] (latch = 1, values = 0, errors = 0, completions = 0, timeout!) at io.reactivex.observers.BaseTestConsumer.fail(BaseTestConsumer.java:191) at io.reactivex.observers.BaseTestConsumer.assertValue(BaseTestConsumer.java:356) at com.wayray.element.core.dao.CharacteristicDaoTest.test_getUserCharacteristicsByName(CharacteristicDaoTest.java:44) at java.lang.reflect.Method.invoke(Native Method) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at io.realm.rule.RunInLooperThread$TestThread.run(RunInLooperThread.java:509)

Steps & Code to Reproduce

Describe your current debugging efforts.

Code Sample

@RunWith(AndroidJUnit4.class)
public class CharacteristicDaoTest {
    @Rule
    public final RunInLooperThread looperThread = new RunInLooperThread(new ElementRealmLibraryModule());

    @RunTestInLooperThread
    @Test
    public final void test_getUserCharacteristicsByName() {
        CarData carData = new CarData();
        TestObserver<List<CarData>> testObserver = new TestObserver<>();
        Realm realm = looperThread.getRealm();
        realm.executeTransaction(realm1 -> realm1.copyToRealm(carData));
        realm
                .where(CarData.class)
                .findAllAsync()
                .asChangesetObservable()
                .map(CollectionChange::getCollection)
                .filter(RealmResults::isLoaded)
                .map(realm::copyFromRealm)
                .doOnDispose(realm::close)
                .subscribe(testObserver);
        testObserver.awaitCount(1);
        testObserver.assertValue(Collections.singletonList(carData));
        testObserver.dispose();
        looperThread.testComplete();
    }
}

Version of Realm and tooling

Realm version(s): ? 5.1.0 Realm sync feature enabled: yes/no no Android Studio version: ? 3.1.2 Which Android version and device: ? Emulator with Android P

Could you possibly explain why this test fails, however this code works in the project?

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
cmelchiorcommented, May 28, 2018

I suspect you are blocking the looper thread with your testObserver.awaitCount(1). If that method is calling CountDownLatch.await() you are blocking the looper thread from processing any notifications which is why your test times out.

This is also why you almost always see our own tests call looperThread.testComplete() from inside a callback. Example: https://github.com/realm/realm-java/blob/master/realm/realm-library/src/androidTest/java/io/realm/RxJavaTests.java#L188

1reaction
epetriyovcommented, May 28, 2018

Thank you very much! You are totally right. After replacing TestObserver with custom Consumer like this:

 CompositeDisposable compositeDisposable = new CompositeDisposable();
        compositeDisposable.add(
                characteristicDao.getUserCharacteristicsByName("userId", "name")
                        .subscribe(characteristicChartValues -> {
                            Assert.assertEquals(characteristicChartValues, Collections.singletonList(characteristicChartValue));
                            compositeDisposable.clear();
                            looperThread.testComplete();
                        }));

my test finished with success.

Read more comments on GitHub >

github_iconTop Results From Across the Web

No results found

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found